ruby_android 0.0.2 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/.name +1 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/encodings.xml +5 -0
  5. data/.idea/misc.xml +5 -0
  6. data/.idea/modules.xml +9 -0
  7. data/.idea/ruby_apk.iml +51 -0
  8. data/.idea/scopes/scope_settings.xml +5 -0
  9. data/.idea/vcs.xml +7 -0
  10. data/.idea/workspace.xml +508 -0
  11. data/.travis.yml +4 -0
  12. data/CHANGELOG.md +51 -0
  13. data/Gemfile +3 -3
  14. data/Gemfile.lock +73 -0
  15. data/LICENSE.txt +2 -2
  16. data/Rakefile +42 -1
  17. data/VERSION +1 -0
  18. data/lib/android/apk.rb +207 -0
  19. data/lib/android/axml_parser.rb +173 -0
  20. data/lib/android/dex/access_flag.rb +74 -0
  21. data/lib/android/dex/dex_object.rb +475 -0
  22. data/lib/android/dex/info.rb +151 -0
  23. data/lib/android/dex/utils.rb +45 -0
  24. data/lib/android/dex.rb +92 -0
  25. data/lib/android/layout.rb +44 -0
  26. data/lib/android/manifest.rb +249 -0
  27. data/lib/android/resource.rb +529 -0
  28. data/lib/android/utils.rb +55 -0
  29. data/lib/ruby_apk.rb +7 -0
  30. data/ruby_android.gemspec +103 -17
  31. data/spec/apk_spec.rb +301 -0
  32. data/spec/axml_parser_spec.rb +67 -0
  33. data/spec/data/sample.apk +0 -0
  34. data/spec/data/sample_AndroidManifest.xml +0 -0
  35. data/spec/data/sample_classes.dex +0 -0
  36. data/spec/data/sample_resources.arsc +0 -0
  37. data/spec/data/sample_resources_utf16.arsc +0 -0
  38. data/spec/data/str_resources.arsc +0 -0
  39. data/spec/dex/access_flag_spec.rb +42 -0
  40. data/spec/dex/dex_object_spec.rb +118 -0
  41. data/spec/dex/info_spec.rb +121 -0
  42. data/spec/dex/utils_spec.rb +56 -0
  43. data/spec/dex_spec.rb +59 -0
  44. data/spec/layout_spec.rb +27 -0
  45. data/spec/manifest_spec.rb +221 -0
  46. data/spec/resource_spec.rb +170 -0
  47. data/spec/ruby_apk_spec.rb +4 -0
  48. data/spec/spec_helper.rb +17 -0
  49. data/spec/utils_spec.rb +90 -0
  50. metadata +112 -27
  51. data/.gitignore +0 -14
  52. data/lib/ruby_android/version.rb +0 -3
  53. data/lib/ruby_android.rb +0 -7
@@ -0,0 +1,475 @@
1
+
2
+ module Android
3
+ class Dex
4
+ # parsing dex object
5
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
6
+ class DexObject
7
+ # @return [Integer] object size
8
+ attr_reader :size
9
+
10
+ def initialize(data, offset)
11
+ @data = data
12
+ @offset = offset
13
+
14
+ @params = {}
15
+ @parsing_off = 0 # parsing offset
16
+ parse()
17
+ @size = @parsing_off
18
+ end
19
+
20
+ # returns symbol keys
21
+ # @return [Array<Symbol>] header key
22
+ def symbols
23
+ @params.keys
24
+ end
25
+
26
+ # @param [Symbol] sym should be included in #symbols
27
+ # @return [Object] dex header value which is related with sym
28
+ def [](sym)
29
+ @params[sym.to_sym]
30
+ end
31
+
32
+ # @return [String]
33
+ def inspect
34
+ str = "<#{self.class}\n"
35
+ @params.each do |key,val|
36
+ str.concat " #{key}: #{val}\n"
37
+ end
38
+ str.concat '>'
39
+ end
40
+
41
+ private
42
+ def parse
43
+ raise 'this method should be overloaded.'
44
+ end
45
+
46
+ def read_value(type)
47
+ types = {
48
+ :byte => [1, 'c'],
49
+ :ubyte => [1, 'C'],
50
+ :short => [2, 's'], #ugh!:depend on machine endian
51
+ :ushort => [2, 'v'],
52
+ :int => [4, 'i'], #ugh!:depend on machine endian
53
+ :uint => [4, 'V'],
54
+ :long => [8, 'q'],
55
+ :ulong => [8, 'Q'],
56
+ }
57
+ len, pack_str = types.fetch(type)
58
+ value = @data[@offset+@parsing_off, len].unpack(pack_str)[0]
59
+ @parsing_off += len
60
+ return value
61
+ end
62
+
63
+ # read short int from data buffer
64
+ # @return [Integer] short value
65
+ def read_sleb
66
+ value, len = Dex::sleb128(@data, @offset + @parsing_off)
67
+ @parsing_off += len
68
+ value
69
+ end
70
+ # read integer from data buffer
71
+ # @return [Integer] integer value
72
+ def read_uleb
73
+ value, len = Dex::uleb128(@data, @offset + @parsing_off)
74
+ @parsing_off += len
75
+ value
76
+ end
77
+ # read integer from data buffer and plus 1
78
+ # @return [Integer] integer value
79
+ def read_uleb128p1
80
+ value, len = Dex::uleb128p1(@data, @offset + @parsing_off)
81
+ @parsing_off += len
82
+ value
83
+ end
84
+ # read various values from data buffer as array
85
+ # @param [Symbol] type
86
+ # @param [Integer] size num of data
87
+ # @return [Array] value array
88
+ def read_value_array(type, size)
89
+ ret_array = []
90
+ size.times { ret_array << read_value(type) }
91
+ ret_array
92
+ end
93
+ # read class values from data buffer as array
94
+ # @param [Class] cls target class
95
+ # @param [Integer] size num of data
96
+ # @return [Array<cls>] object array
97
+ def read_class_array(cls, size)
98
+ ret_array = []
99
+ size.times do
100
+ item = cls.new(@data, @offset + @parsing_off)
101
+ ret_array << item
102
+ @parsing_off += item.size
103
+ end
104
+ ret_array
105
+ end
106
+
107
+ public
108
+ # header_item
109
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
110
+ class Header < DexObject
111
+ def initialize(data)
112
+ super(data, 0)
113
+ end
114
+
115
+ private
116
+ def parse
117
+ @params[:magic] = @data[0, 8]
118
+ @parsing_off += 8
119
+ @params[:checksum] = read_value(:uint)
120
+ @params[:signature] = @data[12, 20]
121
+ @parsing_off += 20
122
+ [
123
+ :file_size, :header_size, :endian_tag, :link_size, :link_off, :map_off,
124
+ :string_ids_size, :string_ids_off, :type_ids_size, :type_ids_off,
125
+ :proto_ids_size, :proto_ids_off, :field_ids_size, :field_ids_off,
126
+ :method_ids_size, :method_ids_off, :class_defs_size, :class_defs_off,
127
+ :data_size, :data_off
128
+ ].each do |key|
129
+ @params[key] = read_value(:uint)
130
+ end
131
+ end
132
+ end
133
+
134
+ # map_list
135
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
136
+ class MapList < DexObject
137
+ private
138
+ def parse
139
+ @params[:size] = read_value(:uint)
140
+ @params[:list] = read_class_array(MapItem, @params[:size])
141
+ end
142
+ end
143
+
144
+ # map_item
145
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
146
+ class MapItem < DexObject
147
+ private
148
+ def parse
149
+ @params[:type] = read_value(:short)
150
+ @params[:unused] = read_value(:short)
151
+ @params[:size] = read_value(:uint)
152
+ @params[:offset] = read_value(:uint)
153
+ end
154
+ end
155
+
156
+ # id_list
157
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
158
+ class IdsList < DexObject
159
+ attr_reader :ids_size
160
+ def initialize(data, off, ids_size)
161
+ @ids_size = ids_size
162
+ super(data, off)
163
+ end
164
+ end
165
+
166
+ # string_id_item
167
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
168
+ class StringIdItem < IdsList
169
+ private
170
+ def parse
171
+ @params[:string_data_off] = read_value_array(:uint, @ids_size)
172
+ end
173
+ end
174
+
175
+ # string_data_item
176
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
177
+ class StringDataItem < DexObject
178
+ def to_s
179
+ @params[:data]
180
+ end
181
+ private
182
+ def mutf8_to_utf8(data, off, ulen)
183
+ mi = 0 # index of mutf8 data
184
+ codepoints = []
185
+ while ulen > 0 do
186
+ b0 = data[off + mi].ord
187
+ bu = (b0 & 0xf0) # b0's upper nibble
188
+ if (b0 & 0x80) == 0 # single byte encoding (0b0xxx_xxxx)
189
+ c = b0
190
+ mi += 1
191
+ ulen -= 1
192
+ elsif bu == 0xc0 || bu == 0xd0 # two-byte encoding (0b110x_xxxx)
193
+ b1 = data[off + mi + 1].ord
194
+ c = (b0 & 0x1f) << 6 | (b1 & 0x3f)
195
+ mi += 2
196
+ ulen -= 1
197
+ elsif bu == 0xe0 # three-byte encoding (0b1110_xxxx)
198
+ b1 = data[off + mi + 1].ord
199
+ b2 = data[off + mi + 2].ord
200
+ c = (b0 & 0x0f) << 12 | (b1 & 0x3f) << 6 | (b2 & 0x3f)
201
+ mi += 3
202
+ ulen -= 1
203
+ if 0xD800 <= c && c <= 0xDBFF # this must be a surrogate pair
204
+ b4 = data[off + mi + 1].ord
205
+ b5 = data[off + mi + 2].ord
206
+ c = ((b1 & 0x0f) + 1) << 16 | (b2 & 0x3f) << 10 | (b4 & 0x0f) << 6 | (b5 & 0x3f)
207
+ mi += 3
208
+ ulen -= 1
209
+ end
210
+ else
211
+ STDERR.puts "unsupported byte: 0x#{'%02X' % b0} @#{mi}"
212
+ c = 0
213
+ mi += 1
214
+ next
215
+ end
216
+ if c != 0
217
+ codepoints << c
218
+ end
219
+ end
220
+ codepoints.pack("U*")
221
+ end
222
+ def parse
223
+ @params[:utf16_size] = read_uleb
224
+ @params[:data] = mutf8_to_utf8(@data, @offset + @parsing_off, @params[:utf16_size])
225
+ end
226
+ end
227
+
228
+ # type_id_item
229
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
230
+ class TypeIdItem < IdsList
231
+ def [](idx)
232
+ raise ArgumentError if idx >= @params[:descriptor_idx].size or idx < 0
233
+ @params[:descriptor_idx][idx]
234
+ end
235
+
236
+ private
237
+ def parse
238
+ @params[:descriptor_idx] = read_value_array(:uint, @ids_size)
239
+ end
240
+ end
241
+
242
+ # proto_id_item
243
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
244
+ class ProtoIdItem < DexObject
245
+ # return parse data size
246
+ # @return bytes
247
+ # @note this method for DexObject#read_class_array (private method)
248
+ def self.size
249
+ 4 * 3
250
+ end
251
+ private
252
+ def parse
253
+ @params[:shorty_idx] = read_value(:uint)
254
+ @params[:return_type_idx] = read_value(:uint)
255
+ @params[:parameters_off] = read_value(:uint)
256
+ end
257
+ end
258
+
259
+ # field_id_item
260
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
261
+ class FieldIdItem < DexObject
262
+ # return parse data size
263
+ # @return bytes
264
+ # @note this method for DexObject#read_class_array (private method)
265
+ def self.size
266
+ 2 * 2 + 4
267
+ end
268
+ private
269
+ def parse
270
+ @params[:class_idx] = read_value(:ushort)
271
+ @params[:type_idx] = read_value(:ushort)
272
+ @params[:name_idx] = read_value(:uint)
273
+ end
274
+ end
275
+
276
+ # method_id_item
277
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
278
+ class MethodIdItem < DexObject
279
+ # return parse data size
280
+ # @return bytes
281
+ # @note this method for DexObject#read_class_array (private method)
282
+ def self.size
283
+ 2 * 2 + 4
284
+ end
285
+ def parse
286
+ @params[:class_idx] = read_value(:ushort)
287
+ @params[:proto_idx] = read_value(:ushort)
288
+ @params[:name_idx] = read_value(:uint)
289
+ end
290
+ end
291
+
292
+ # class_def_item
293
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
294
+ # @!attribute [r] class_data_item
295
+ # @return [ClassDataItem] class_data_item of this class
296
+ class ClassDefItem < DexObject
297
+ # @return [Integer] bytes
298
+ def self.size
299
+ 4 * 8
300
+ end
301
+
302
+ def class_data_item
303
+ # description of class_data_off of class_def_item.
304
+ # offset from the start of the file to the associated class data
305
+ # for this item, or 0 if there is no class data for this class.
306
+ if @params[:class_data_off] != 0
307
+ @class_data_item ||= ClassDataItem.new(@data, @params[:class_data_off])
308
+ else
309
+ nil
310
+ end
311
+ end
312
+
313
+ private
314
+ def parse
315
+ @params[:class_idx] = read_value(:uint)
316
+ @params[:access_flags] = read_value(:uint)
317
+ @params[:superclass_idx] = read_value(:uint)
318
+ @params[:interfaces_off] = read_value(:uint)
319
+ @params[:source_file_idx] = read_value(:uint)
320
+ @params[:annotations_off] = read_value(:uint)
321
+ @params[:class_data_off] = read_value(:uint)
322
+ @params[:static_values_off] = read_value(:uint) # TODO: not implemented encoded_array_item
323
+ end
324
+ end
325
+
326
+ # class_data_item
327
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
328
+ class ClassDataItem < DexObject
329
+ private
330
+ def parse
331
+ @params[:static_fields_size] = read_uleb
332
+ @params[:instance_fields_size] = read_uleb
333
+ @params[:direct_methods_size] = read_uleb
334
+ @params[:virtual_methods_size] = read_uleb
335
+ @params[:static_fields] = read_class_array(EncodedField, @params[:static_fields_size])
336
+ @params[:instance_fields] = read_class_array(EncodedField, @params[:instance_fields_size])
337
+ @params[:direct_methods] = read_class_array(EncodedMethod, @params[:direct_methods_size])
338
+ @params[:virtual_methods] = read_class_array(EncodedMethod, @params[:virtual_methods_size])
339
+ end
340
+ end
341
+
342
+ # encoded_field
343
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
344
+ class EncodedField < DexObject
345
+ private
346
+ def parse
347
+ @params[:field_idx_diff] = read_uleb
348
+ @params[:access_flags] = read_uleb
349
+ end
350
+ end
351
+
352
+ # encoded_method
353
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
354
+ # @!attribute [r] code_item
355
+ # @return [CodeItem] code_item of the method
356
+ class EncodedMethod < DexObject
357
+ def code_item
358
+ # description of code_off in code_data_item.
359
+ # offset from the start of the file to the code structure for this method,
360
+ # or 0 if this method is either abstract or native.
361
+ unless @params[:code_off] == 0
362
+ @code_item ||= CodeItem.new(@data, @params[:code_off])
363
+ else
364
+ nil
365
+ end
366
+ end
367
+
368
+ private
369
+ def parse
370
+ @params[:method_idx_diff] = read_uleb
371
+ @params[:access_flags] = read_uleb
372
+ @params[:code_off] = read_uleb
373
+ end
374
+ end
375
+
376
+
377
+ # type_list
378
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
379
+ class TypeList < DexObject
380
+ private
381
+ def parse
382
+ @params[:size] = read_value(:uint)
383
+ @params[:list] = read_value_array(:ushort, @params[:size])
384
+ end
385
+ end
386
+
387
+ # code_item
388
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
389
+ # @!attribute [r] debug_info_item
390
+ # @return [DebugInfoItem] debug_info_item of this code
391
+ class CodeItem < DexObject
392
+ def debug_info_item
393
+ unless @params[:debug_info_off] == 0
394
+ @debug_info_item ||= DebugInfoItem.new(@data, @params[:debug_info_off])
395
+ else
396
+ nil
397
+ end
398
+ end
399
+
400
+ private
401
+ def parse
402
+ @params[:registers_size] = read_value(:ushort)
403
+ @params[:ins_size] = read_value(:ushort)
404
+ @params[:outs_size] = read_value(:ushort)
405
+ @params[:tries_size] = read_value(:ushort)
406
+ @params[:debug_info_off] = read_value(:uint)
407
+ @params[:insns_size] = read_value(:uint) # size of the instructions list
408
+ @params[:insns] = read_value_array(:ushort, @params[:insns_size])
409
+ read_value(:ushort) if ((@params[:insns_size] % 2) == 1) # for four-byte aligned
410
+ if @params[:tries_size] > 0
411
+ # This element is only present if tries_size is non-zero.
412
+ @params[:tries] = read_class_array(TryItem, @params[:tries_size])
413
+ # This element is only present if tries_size is non-zero.
414
+ @params[:handlers] = EncodedCatchHandlerList.new(@data, @offset + @parsing_off)
415
+ @parsing_off += @params[:handlers].size
416
+ end
417
+ end
418
+ end
419
+
420
+ # try_item
421
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
422
+ class TryItem < DexObject
423
+ private
424
+ def parse
425
+ @params[:start_addr] = read_value(:uint)
426
+ @params[:insn_count] = read_value(:ushort)
427
+ @params[:handler_off] = read_value(:ushort)
428
+ end
429
+ end
430
+
431
+ # encoded_catch_handler_list
432
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
433
+ class EncodedCatchHandlerList < DexObject
434
+ private
435
+ def parse
436
+ @params[:size] = read_uleb
437
+ @params[:list] = read_class_array(EncodedCatchHandler, @params[:size])
438
+ end
439
+ end
440
+
441
+ # encoded_catch_handler
442
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
443
+ class EncodedCatchHandler < DexObject
444
+ private
445
+ def parse
446
+ @params[:size] = read_sleb
447
+ @params[:list] = read_class_array(EncodedTypeAddrPair, @params[:size].abs)
448
+ @params[:catch_all_addr] = read_uleb if @params[:size] <= 0
449
+ end
450
+ end
451
+
452
+ # encoded_type_addr_pair
453
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
454
+ class EncodedTypeAddrPair < DexObject
455
+ private
456
+ def parse
457
+ @params[:type_idx] = read_uleb
458
+ @params[:addr] = read_uleb
459
+ end
460
+ end
461
+
462
+ # debug_info_item
463
+ # @see http://source.android.com/devices/tech/dalvik/dex-format.html
464
+ class DebugInfoItem < DexObject
465
+ private
466
+ def parse
467
+ @params[:line_start] = read_uleb
468
+ @params[:parameters_size] = read_uleb
469
+ @params[:parameter_names] = []
470
+ @params[:parameters_size].times { @params[:parameter_names] << read_uleb128p1 }
471
+ end
472
+ end
473
+ end
474
+ end
475
+ end
@@ -0,0 +1,151 @@
1
+ require_relative 'dex_object'
2
+
3
+ module Android
4
+ class Dex
5
+ # class information in dex
6
+ # @!attribute [r] name
7
+ # @return [String] class name
8
+ # @!attribute [r] super_class
9
+ # @return [String] super class name
10
+ class ClassInfo
11
+ # no index flag
12
+ NO_INDEX = 0xffffffff
13
+
14
+ # @return [ClassAccessFlag]
15
+ attr_reader :access_flags
16
+ # @return [Array<FieldInfo>] static fields
17
+ attr_reader :static_fields
18
+ # @return [Array<FieldInfo>] instance fields
19
+ attr_reader :instance_fields
20
+ # @return [Array<MethodInfo>] direct methods
21
+ attr_reader :direct_methods
22
+ # @return [Array<MethodInfo>] virtual methods
23
+ attr_reader :virtual_methods
24
+
25
+ # @return [DexObject::ClassDataItem]
26
+ attr_reader :class_data
27
+ # @return [DexObject::ClassDefItem]
28
+ attr_reader :class_def
29
+
30
+ def name
31
+ @dex.type_resolve(@class_def[:class_idx])
32
+ end
33
+ def super_class
34
+ if @class_def[:superclass_idx] != NO_INDEX
35
+ @super_class = @dex.type_resolve(@class_def[:superclass_idx])
36
+ else
37
+ nil
38
+ end
39
+ end
40
+ # @param [Dex::ClassDefItem] class_def
41
+ # @param [Dex] dex dex class instance
42
+ def initialize(class_def, dex)
43
+ @class_def = class_def
44
+ @dex = dex
45
+ @access_flags = ClassAccessFlag.new(@class_def[:access_flags])
46
+ @class_data = @class_def.class_data_item
47
+ @static_fields = @instance_fields = @direct_methods = @virtual_methods = []
48
+ unless @class_data.nil?
49
+ @static_fields = cls2info(@class_data[:static_fields], FieldInfo, :field_idx_diff)
50
+ @instance_fields = cls2info(@class_data[:instance_fields], FieldInfo, :field_idx_diff)
51
+ @direct_methods = cls2info(@class_data[:direct_methods], MethodInfo, :method_idx_diff)
52
+ @virtual_methods = cls2info(@class_data[:virtual_methods], MethodInfo, :method_idx_diff)
53
+ end
54
+ end
55
+
56
+ # @return [String] class difinition
57
+ def definition
58
+ ret = "#{access_flags} class #{name}"
59
+ super_class.nil? ? ret : ret + " extends #{super_class}"
60
+ end
61
+
62
+ private
63
+ def cls2info(arr, cls, idx_key)
64
+ idx = 0
65
+ ret = []
66
+ arr.each do |item|
67
+ idx += item[idx_key]
68
+ ret << cls.new(item, idx, @dex)
69
+ end
70
+ ret
71
+ end
72
+ end
73
+
74
+ # field info object
75
+ # @!attribute [r] name
76
+ # @return [String] field name
77
+ # @!attribute [r] type
78
+ # @return [String] field type
79
+ class FieldInfo
80
+ # @return [ClassAccessFlag]
81
+ attr_reader :access_flags
82
+
83
+ def name
84
+ @dex.strings[@dex.field_ids[@field_id][:name_idx]]
85
+ end
86
+ def type
87
+ @dex.type_resolve(@dex.field_ids[@field_id][:type_idx])
88
+ end
89
+ def initialize(encoded_field, field_id, dex)
90
+ @dex = dex
91
+ @encoded_field = encoded_field
92
+ @field_id = field_id
93
+ @access_flags = ClassAccessFlag.new(encoded_field[:access_flags])
94
+ end
95
+
96
+ # @return [String] field definition
97
+ def definition
98
+ "#{@access_flags.to_s} #{type} #{name}"
99
+ end
100
+ end
101
+
102
+ # method info object
103
+ # @!attribute [r] name
104
+ # @return [String] method name
105
+ # @!attribute [r] ret_type
106
+ # @return [String] return type of the method
107
+ # @!attribute [r] parameters
108
+ # @return [Array<String>] method parameters
109
+ class MethodInfo
110
+ # @return [MethodAccessFlag]
111
+ attr_reader :access_flags
112
+
113
+ def initialize(encoded_method, method_id, dex)
114
+ @encoded_method = encoded_method
115
+ @method_id = method_id
116
+ @dex = dex
117
+ @access_flags = MethodAccessFlag.new(encoded_method[:access_flags])
118
+ end
119
+ def name
120
+ @dex.strings[@dex.method_ids[@method_id][:name_idx]]
121
+ end
122
+ def ret_type
123
+ @dex.type_resolve(proto[:return_type_idx])
124
+ end
125
+ def parameters
126
+ unless proto[:parameters_off] == 0
127
+ list = DexObject::TypeList.new(@dex.data, proto[:parameters_off])
128
+ list[:list].map { |item| @dex.type_resolve(item) }
129
+ else
130
+ []
131
+ end
132
+ end
133
+
134
+ # @return [String] method definition string
135
+ def definition
136
+ "#{access_flags.to_s} #{ret_type} #{name}(#{parameters.join(', ')});"
137
+ end
138
+
139
+ # @return [DexObject::CodeItem]
140
+ def code_item
141
+ @encoded_method.code_item
142
+ end
143
+
144
+ private
145
+ def proto
146
+ @dex.proto_ids[@dex.method_ids[@method_id][:proto_idx]]
147
+ end
148
+ end
149
+
150
+ end
151
+ end
@@ -0,0 +1,45 @@
1
+ module Android
2
+ class Dex
3
+ class << self
4
+ # parse uleb128(unsigned integer) data
5
+ # @param [String] data target byte data
6
+ # @param [Integer] offset
7
+ # @return [Integer, Integer] parsed value and parsed byte length
8
+ # @see http://en.wikipedia.org/wiki/LEB128
9
+ def uleb128(data, offset=0)
10
+ result = 0
11
+ shift = 0
12
+ d = data[offset...data.size]
13
+ (0..4).each do |i|
14
+ byte = d.getbyte(i)
15
+ result |= ((byte & 0x7f) << shift)
16
+ return result, i+1 if ((byte & 0x80) == 0)
17
+ shift += 7
18
+ end
19
+ end
20
+ # parse uleb128 + 1 data
21
+ # @param [String] data target byte data
22
+ # @param [Integer] offset
23
+ # @return [Integer, Integer] parsed value and parsed byte length
24
+ def uleb128p1(data, offset=0)
25
+ ret, len = self.uleb128(data, offset)
26
+ return (ret - 1), len
27
+ end
28
+ # parse sleb128(signed integer) data
29
+ # @param [String] data target byte data
30
+ # @param [Integer] offset
31
+ # @return [Integer, Integer] parsed value and parsed byte length
32
+ def sleb128(data, offset=0)
33
+ result = 0
34
+ shift = 0
35
+ d = data[offset...data.size]
36
+ (0..4).each do |i|
37
+ byte = d.getbyte(i)
38
+ result |=((byte & 0x7F) << shift)
39
+ return (0 == (byte & 0x40) ? result : result - (1 << (shift+7))), i+1 if ((byte & 0x80) == 0)
40
+ shift += 7
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end