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
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,51 @@
1
+ # ChangeLog
2
+ ## 0.7.2
3
+ * updated rubyzip from wrong dependency '<1.0.0'
4
+
5
+ ## 0.7.1
6
+ *
7
+
8
+ ## 0.7.0
9
+ * implement Apk#signs, Apk#certificates and Manifest#version_name (#14, #15)
10
+ * bugfix
11
+
12
+ ## 0.6.0
13
+ * implement Android::Apk#layouts(#10), Android::Apk#icon(#11), Android::Apk#label(#12),
14
+ * fix bug (#13)
15
+
16
+ ## 0.5.1
17
+ * [#8] add Android::Manifest#label
18
+ * [#7] fix wrong boolean value in manifest parser
19
+ * [#6] add accessor Android::Manifest#doc
20
+
21
+ ## 0.5.0
22
+ * [issue #1] implement Android::Resource#find, #res_readable_id, #res_hex_id methods
23
+
24
+ ## 0.4.2
25
+ * fix bugs(#2, #3)
26
+ * divide change log from readme
27
+
28
+ ## 0.4.1
29
+ * fix typo
30
+ * add document
31
+
32
+ ## 0.4.0
33
+ * add resource parser
34
+ * enhance dex parser
35
+
36
+ ## 0.3.0
37
+ * add and change name space
38
+ * add Android::Utils module and some util methods
39
+ * add Apk#entry, Apk#each_entry, and Apk#time methods,
40
+
41
+ ## 0.2.0
42
+ * update documents
43
+ * add Apk::Dex#each_strings, Apk::Dex#each_class_names
44
+
45
+ ## 0.1.2
46
+ * fix bug(improve android binary xml parser)
47
+
48
+ ## 0.1.1
49
+ * fix bug(failed to initialize Apk::Manifest::Meta class)
50
+ * replace iconv to String#encode(for ruby1.9)
51
+
data/Gemfile CHANGED
@@ -7,9 +7,9 @@ gem "rubyzip", ">= 1.1.6"
7
7
  # Add dependencies to develop your gem here.
8
8
  # Include everything needed to run rake, tests, features, etc.
9
9
  group :development do
10
- gem "rspec", ">= 2.11.0"
11
- gem "bundler", ">= 1.5.2"
12
- gem "jeweler", ">= 2.0.0"
10
+ gem "rspec", "~> 2.11.0"
11
+ gem "bundler", ">= 1.3.0"
12
+ gem "jeweler", "~> 1.8.7"
13
13
  gem "yard", require: false
14
14
  gem "redcarpet"
15
15
  gem "simplecov", require: false
data/Gemfile.lock ADDED
@@ -0,0 +1,73 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.3.5)
5
+ builder (3.2.2)
6
+ diff-lcs (1.1.3)
7
+ faraday (0.8.8)
8
+ multipart-post (~> 1.2.0)
9
+ git (1.2.6)
10
+ github_api (0.10.1)
11
+ addressable
12
+ faraday (~> 0.8.1)
13
+ hashie (>= 1.2)
14
+ multi_json (~> 1.4)
15
+ nokogiri (~> 1.5.2)
16
+ oauth2
17
+ hashie (2.0.5)
18
+ highline (1.6.19)
19
+ httpauth (0.2.0)
20
+ jeweler (1.8.7)
21
+ builder
22
+ bundler (~> 1.0)
23
+ git (>= 1.2.5)
24
+ github_api (= 0.10.1)
25
+ highline (>= 1.6.15)
26
+ nokogiri (= 1.5.10)
27
+ rake
28
+ rdoc
29
+ json (1.8.0)
30
+ jwt (0.1.8)
31
+ multi_json (>= 1.5)
32
+ multi_json (1.8.0)
33
+ multi_xml (0.5.5)
34
+ multipart-post (1.2.0)
35
+ nokogiri (1.5.10)
36
+ oauth2 (0.9.2)
37
+ faraday (~> 0.8)
38
+ httpauth (~> 0.2)
39
+ jwt (~> 0.1.4)
40
+ multi_json (~> 1.0)
41
+ multi_xml (~> 0.5)
42
+ rack (~> 1.2)
43
+ rack (1.5.2)
44
+ rake (10.1.0)
45
+ rdoc (4.0.1)
46
+ json (~> 1.4)
47
+ redcarpet (3.0.0)
48
+ rspec (2.11.0)
49
+ rspec-core (~> 2.11.0)
50
+ rspec-expectations (~> 2.11.0)
51
+ rspec-mocks (~> 2.11.0)
52
+ rspec-core (2.11.1)
53
+ rspec-expectations (2.11.3)
54
+ diff-lcs (~> 1.1.3)
55
+ rspec-mocks (2.11.3)
56
+ rubyzip (1.1.6)
57
+ simplecov (0.7.1)
58
+ multi_json (~> 1.0)
59
+ simplecov-html (~> 0.7.1)
60
+ simplecov-html (0.7.1)
61
+ yard (0.8.7.2)
62
+
63
+ PLATFORMS
64
+ ruby
65
+
66
+ DEPENDENCIES
67
+ bundler (>= 1.3.0)
68
+ jeweler (~> 1.8.7)
69
+ redcarpet
70
+ rspec (~> 2.11.0)
71
+ rubyzip (>= 1.1.6)
72
+ simplecov
73
+ yard
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
- Copyright (c) 2014 Michal Tajchert
1
+ (The MIT License)
2
2
 
3
- MIT License
3
+ Copyright (c) 2012 Securebrain
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,2 +1,43 @@
1
- require "bundler/gem_tasks"
1
+ # encoding: utf-8
2
2
 
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "ruby_android"
18
+ gem.homepage = "https://github.com/tajchert/ruby_apk"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{static analysis tool for android apk}
21
+ gem.description = %Q{static analysis tool for android apk}
22
+ gem.email = "thetajchert@gmail.com"
23
+ gem.authors = ["Michal Tajchert","SecureBrain"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+
35
+ task :default => :spec
36
+
37
+ require 'yard'
38
+ require 'yard/rake/yardoc_task'
39
+ YARD::Rake::YardocTask.new do |t|
40
+ t.files = ['lib/**/*.rb']
41
+ t.options = []
42
+ t.options << '--debug' << '--verbose' if $trace
43
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.2
@@ -0,0 +1,207 @@
1
+ require 'zip' # need rubyzip gem -> doc: http://rubyzip.sourceforge.net/
2
+ require 'digest/md5'
3
+ require 'digest/sha1'
4
+ require 'digest/sha2'
5
+ require 'openssl'
6
+
7
+ module Android
8
+ class NotApkFileError < StandardError; end
9
+ class NotFoundError < StandardError; end
10
+
11
+ # apk object class
12
+ class Apk
13
+
14
+ # @return [String] apk file path
15
+ attr_reader :path
16
+ # @return [Android::Manifest] manifest instance
17
+ # @return [nil] when parsing manifest is failed.
18
+ attr_reader :manifest
19
+ # @return [Android::Dex] dex instance
20
+ # @return [nil] when parsing dex is failed.
21
+ attr_reader :dex
22
+ # @return [String] binary data of apk
23
+ attr_reader :bindata
24
+ # @return [Resource] resouce data
25
+ # @return [nil] when parsing resource is failed.
26
+ attr_reader :resource
27
+
28
+ # AndroidManifest file name
29
+ MANIFEST = 'AndroidManifest.xml'
30
+ # dex file name
31
+ DEX = 'classes.dex'
32
+ # resource file name
33
+ RESOURCE = 'resources.arsc'
34
+
35
+ # create new apk object
36
+ # @param [String] filepath apk file path
37
+ # @raise [Android::NotFoundError] path file does'nt exist
38
+ # @raise [Android::NotApkFileError] path file is not Apk file.
39
+ def initialize(filepath)
40
+ @path = filepath
41
+ raise NotFoundError, "'#{filepath}'" unless File.exist? @path
42
+ begin
43
+ @zip = Zip::File.open(@path)
44
+ rescue Zip::Error => e
45
+ raise NotApkFileError, e.message
46
+ end
47
+
48
+ @bindata = File.open(@path, 'rb') {|f| f.read }
49
+ @bindata.force_encoding(Encoding::ASCII_8BIT)
50
+ raise NotApkFileError, "manifest file is not found." if @zip.find_entry(MANIFEST).nil?
51
+ begin
52
+ @resource = Android::Resource.new(self.file(RESOURCE))
53
+ rescue => e
54
+ $stderr.puts "failed to parse resource:#{e}"
55
+ #$stderr.puts e.backtrace
56
+ end
57
+ begin
58
+ @manifest = Android::Manifest.new(self.file(MANIFEST), @resource)
59
+ rescue => e
60
+ $stderr.puts "failed to parse manifest:#{e}"
61
+ #$stderr.puts e.backtrace
62
+ end
63
+ begin
64
+ @dex = Android::Dex.new(self.file(DEX))
65
+ rescue => e
66
+ $stderr.puts "failed to parse dex:#{e}"
67
+ #$stderr.puts e.backtrace
68
+ end
69
+ end
70
+
71
+ # return apk file size
72
+ # @return [Integer] bytes
73
+ def size
74
+ @bindata.size
75
+ end
76
+
77
+ # return hex digest string of apk file
78
+ # @param [Symbol] type hash digest type(:sha1, sha256, :md5)
79
+ # @return [String] hex digest string
80
+ # @raise [ArgumentError] type is knknown type
81
+ def digest(type = :sha1)
82
+ case type
83
+ when :sha1
84
+ Digest::SHA1.hexdigest(@bindata)
85
+ when :sha256
86
+ Digest::SHA256.hexdigest(@bindata)
87
+ when :md5
88
+ Digest::MD5.hexdigest(@bindata)
89
+ else
90
+ raise ArgumentError
91
+ end
92
+ end
93
+
94
+ # returns date of AndroidManifest.xml as Apk date
95
+ # @return [Time]
96
+ def time
97
+ entry(MANIFEST).time
98
+ end
99
+
100
+ # @yield [name, data]
101
+ # @yieldparam [String] name file name in apk
102
+ # @yieldparam [String] data file data in apk
103
+ def each_file
104
+ @zip.each do |entry|
105
+ next unless entry.file?
106
+ yield entry.name, @zip.read(entry)
107
+ end
108
+ end
109
+
110
+ # find and return binary data with name
111
+ # @param [String] name file name in apk(fullpath)
112
+ # @return [String] binary data
113
+ # @raise [NotFoundError] when 'name' doesn't exist in the apk
114
+ def file(name) # get data by entry name(path)
115
+ @zip.read(entry(name))
116
+ end
117
+
118
+ # @yield [entry]
119
+ # @yieldparam [Zip::Entry] entry zip entry
120
+ def each_entry
121
+ @zip.each do |entry|
122
+ next unless entry.file?
123
+ yield entry
124
+ end
125
+ end
126
+
127
+ # find and return zip entry with name
128
+ # @param [String] name file name in apk(fullpath)
129
+ # @return [Zip::ZipEntry] zip entry object
130
+ # @raise [NotFoundError] when 'name' doesn't exist in the apk
131
+ def entry(name)
132
+ entry = @zip.find_entry(name)
133
+ raise NotFoundError, "'#{name}'" if entry.nil?
134
+ return entry
135
+ end
136
+
137
+ # find files which is matched with block condition
138
+ # @yield [name, data] find condition
139
+ # @yieldparam [String] name file name in apk
140
+ # @yieldparam [String] data file data in apk
141
+ # @yieldreturn [Array] Array of matched entry name
142
+ # @return [Array] Array of matched entry name
143
+ # @example
144
+ # apk = Apk.new(path)
145
+ # elf_files = apk.find { |name, data| data[0..3] == [0x7f, 0x45, 0x4c, 0x46] } # ELF magic number
146
+ def find(&block)
147
+ found = []
148
+ self.each_file do |name, data|
149
+ ret = block.call(name, data)
150
+ found << name if ret
151
+ end
152
+ found
153
+ end
154
+
155
+ # extract icon data from AndroidManifest and resource.
156
+ # @return [Hash{ String => String }] hash key is icon filename. value is image data
157
+ # @raise [NotFoundError]
158
+ # @since 0.6.0
159
+ def icon
160
+ icon_id = @manifest.doc.elements['/manifest/application'].attributes['icon']
161
+ if /^@(\w+\/\w+)|(0x[0-9a-fA-F]{8})$/ =~ icon_id
162
+ drawables = @resource.find(icon_id)
163
+ Hash[drawables.map {|name| [name, file(name)] }]
164
+ else
165
+ { icon_id => file(icon_id) } # ugh!: not tested!!
166
+ end
167
+ end
168
+
169
+ # get application label from AndroidManifest and resources.
170
+ # @param [String] lang language code like 'ja', 'cn', ...
171
+ # @return [String] application label string
172
+ # @return [nil] when label is not found
173
+ # @deprecated move to {Android::Manifest#label}
174
+ # @since 0.6.0
175
+ def label(lang=nil)
176
+ @manifest.label
177
+ end
178
+
179
+ # get screen layout xml datas
180
+ # @return [Hash{ String => Android::Layout }] key: laytout file path, value: layout object
181
+ # @since 0.6.0
182
+ def layouts
183
+ @layouts ||= Layout.collect_layouts(self) # lazy parse
184
+ end
185
+
186
+ # apk's signature information
187
+ # @return [Hash{ String => OpenSSL::PKCS7 } ] key: sign file path, value: signature
188
+ # @since 0.7.0
189
+ def signs
190
+ signs = {}
191
+ self.each_file do |path, data|
192
+ # find META-INF/xxx.{RSA|DSA}
193
+ next unless path =~ /^META-INF\// && data.unpack("CC") == [0x30, 0x82]
194
+ signs[path] = OpenSSL::PKCS7.new(data)
195
+ end
196
+ signs
197
+ end
198
+
199
+ # certificate info which is used for signing
200
+ # @return [Hash{String => OpenSSL::X509::Certificate }] key: sign file path, value: first certficate in the sign file
201
+ # @since 0.7.0
202
+ def certificates
203
+ return Hash[self.signs.map{|path, sign| [path, sign.certificates.first] }]
204
+ end
205
+ end
206
+ end
207
+
@@ -0,0 +1,173 @@
1
+ require 'rexml/document'
2
+ require 'stringio'
3
+
4
+
5
+ module Android
6
+ # binary AXML parser
7
+ # @see https://android.googlesource.com/platform/frameworks/base.git Android OS frameworks source
8
+ # @note
9
+ # refer to Android OS framework code:
10
+ #
11
+ # /frameworks/base/include/androidfw/ResourceTypes.h,
12
+ #
13
+ # /frameworks/base/libs/androidfw/ResourceTypes.cpp
14
+ class AXMLParser
15
+ def self.axml?(data)
16
+ (data[0..3] == "\x03\x00\x08\x00")
17
+ end
18
+
19
+ # axml parse error
20
+ class ReadError < StandardError; end
21
+
22
+ TAG_START_DOC = 0x00100100
23
+ TAG_END_DOC = 0x00100101
24
+ TAG_START = 0x00100102
25
+ TAG_END = 0x00100103
26
+ TAG_TEXT = 0x00100104
27
+ TAG_CDSECT = 0x00100105
28
+ TAG_ENTITY_REF= 0x00100106
29
+
30
+ VAL_TYPE_NULL =0
31
+ VAL_TYPE_REFERENCE =1
32
+ VAL_TYPE_ATTRIBUTE =2
33
+ VAL_TYPE_STRING =3
34
+ VAL_TYPE_FLOAT =4
35
+ VAL_TYPE_DIMENSION =5
36
+ VAL_TYPE_FRACTION =6
37
+ VAL_TYPE_INT_DEC =16
38
+ VAL_TYPE_INT_HEX =17
39
+ VAL_TYPE_INT_BOOLEAN =18
40
+ VAL_TYPE_INT_COLOR_ARGB8 =28
41
+ VAL_TYPE_INT_COLOR_RGB8 =29
42
+ VAL_TYPE_INT_COLOR_ARGB4 =30
43
+ VAL_TYPE_INT_COLOR_RGB4 =31
44
+
45
+ # @return [Array<String>] strings defined in axml
46
+ attr_reader :strings
47
+
48
+ # @param [String] axml binary xml data
49
+ def initialize(axml)
50
+ @io = StringIO.new(axml, "rb")
51
+ @strings = []
52
+ end
53
+
54
+ # parse binary xml
55
+ # @return [REXML::Document]
56
+ def parse
57
+ @doc = REXML::Document.new
58
+ @doc << REXML::XMLDecl.new
59
+
60
+ @num_str = word(4*4)
61
+ @xml_offset = word(3*4)
62
+
63
+ @parents = [@doc]
64
+ @ns = []
65
+ parse_strings
66
+ parse_tags
67
+ @doc
68
+ end
69
+
70
+
71
+ # read one word(4byte) as integer
72
+ # @param [Integer] offset offset from top position. current position is used if ofset is nil
73
+ # @return [Integer] little endian word value
74
+ def word(offset=nil)
75
+ @io.pos = offset unless offset.nil?
76
+ @io.read(4).unpack("V")[0]
77
+ end
78
+
79
+ # read 2byte as short integer
80
+ # @param [Integer] offset offset from top position. current position is used if ofset is nil
81
+ # @return [Integer] little endian unsign short value
82
+ def short(offset)
83
+ @io.pos = offset unless offset.nil?
84
+ @io.read(2).unpack("v")[0]
85
+ end
86
+
87
+ # relace string table parser
88
+ def parse_strings
89
+ strpool = Resource::ResStringPool.new(@io.string, 8) # ugh!
90
+ @strings = strpool.strings
91
+ end
92
+
93
+ # parse tag
94
+ def parse_tags
95
+ # skip until START_TAG
96
+ pos = @xml_offset
97
+ pos += 4 until (word(pos) == TAG_START) #ugh!
98
+ @io.pos -= 4
99
+
100
+ # read tags
101
+ #puts "start tag parse: %d(%#x)" % [@io.pos, @io.pos]
102
+ until @io.eof?
103
+ last_pos = @io.pos
104
+ tag, tag1, line, tag3, ns_id, name_id = @io.read(4*6).unpack("V*")
105
+ case tag
106
+ when TAG_START
107
+ tag6, num_attrs, tag8 = @io.read(4*3).unpack("V*")
108
+ elem = REXML::Element.new(@strings[name_id])
109
+ #puts "start tag %d(%#x): #{@strings[name_id]} attrs:#{num_attrs}" % [last_pos, last_pos]
110
+ @parents.last.add_element elem
111
+ num_attrs.times do
112
+ key, val = parse_attribute
113
+ elem.add_attribute(key, val)
114
+ end
115
+ @parents.push elem
116
+ when TAG_END
117
+ @parents.pop
118
+ when TAG_END_DOC
119
+ break
120
+ when TAG_TEXT
121
+ text = REXML::Text.new(@strings[ns_id])
122
+ @parents.last.text = text
123
+ dummy = @io.read(4*1).unpack("V*") # skip 4bytes
124
+ when TAG_START_DOC, TAG_CDSECT, TAG_ENTITY_REF
125
+ # not implemented yet.
126
+ else
127
+ raise ReadError, "pos=%d(%#x)[tag:%#x]" % [last_pos, last_pos, tag]
128
+ end
129
+ end
130
+ end
131
+
132
+ # parse attribute of a element
133
+ def parse_attribute
134
+ ns_id, name_id, val_str_id, flags, val = @io.read(4*5).unpack("V*")
135
+ key = @strings[name_id]
136
+ unless ns_id == 0xFFFFFFFF
137
+ ns = @strings[ns_id]
138
+ prefix = ns.sub(/.*\//,'')
139
+ unless @ns.include? ns
140
+ @ns << ns
141
+ @doc.root.add_namespace(prefix, ns)
142
+ end
143
+ key = "#{prefix}:#{key}"
144
+ end
145
+ value = convert_value(val_str_id, flags, val)
146
+ return key, value
147
+ end
148
+
149
+
150
+ def convert_value(val_str_id, flags, val)
151
+ unless val_str_id == 0xFFFFFFFF
152
+ value = @strings[val_str_id]
153
+ else
154
+ type = flags >> 24
155
+ case type
156
+ when VAL_TYPE_NULL
157
+ value = nil
158
+ when VAL_TYPE_REFERENCE
159
+ value = "@%#x" % val # refered resource id.
160
+ when VAL_TYPE_INT_DEC
161
+ value = val
162
+ when VAL_TYPE_INT_HEX
163
+ value = "%#x" % val
164
+ when VAL_TYPE_INT_BOOLEAN
165
+ value = ((val == 0xFFFFFFFF) || (val==1)) ? true : false
166
+ else
167
+ value = "[%#x, flag=%#x]" % [val, flags]
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ end
@@ -0,0 +1,74 @@
1
+
2
+ module Android
3
+ class Dex
4
+ # access flag object
5
+ class AccessFlag
6
+ # @return [Integer] flag value
7
+ attr_reader :flag
8
+ def initialize(flag)
9
+ @flag = flag
10
+ end
11
+ end
12
+
13
+ # access flag object for class in dex
14
+ class ClassAccessFlag < AccessFlag
15
+ ACCESSORS = [
16
+ {value:0x1, name:'public'},
17
+ {value:0x2, name:'private'},
18
+ {value:0x4, name:'protected'},
19
+ {value:0x8, name:'static'},
20
+ {value:0x10, name:'final'},
21
+ {value:0x20, name:'synchronized'},
22
+ {value:0x40, name:'volatile'},
23
+ {value:0x80, name:'transient'},
24
+ {value:0x100, name:'native'},
25
+ {value:0x200, name:'interface'},
26
+ {value:0x400, name:'abstract'},
27
+ {value:0x800, name:'strict'},
28
+ {value:0x1000, name:'synthetic'},
29
+ {value:0x2000, name:'annotation'},
30
+ {value:0x4000, name:'enum'},
31
+ #{value:0x8000, name:'unused'},
32
+ {value:0x10000, name:'constructor'},
33
+ {value:0x20000, name:'declared-synchronized'},
34
+ ]
35
+
36
+ # convert access flag to string
37
+ # @return [String]
38
+ def to_s
39
+ ACCESSORS.select{|e| ((e[:value] & @flag) != 0) }.map{|e| e[:name] }.join(' ')
40
+ end
41
+ end
42
+
43
+ # access flag object for method in dex
44
+ class MethodAccessFlag < AccessFlag
45
+ ACCESSORS = [
46
+ {value: 0x1, name:'public'},
47
+ {value: 0x2, name:'private'},
48
+ {value: 0x4, name:'protected'},
49
+ {value: 0x8, name:'static'},
50
+ {value: 0x10, name:'final'},
51
+ {value: 0x20, name:'synchronized'},
52
+ {value: 0x40, name:'bridge'},
53
+ {value: 0x80, name:'varargs'},
54
+ {value: 0x100, name:'native'},
55
+ {value: 0x200, name:'interface'},
56
+ {value: 0x400, name:'abstract'},
57
+ {value: 0x800, name:'strict'},
58
+ {value: 0x1000, name:'synthetic'},
59
+ {value: 0x2000, name:'annotation'},
60
+ {value: 0x4000, name:'enum'},
61
+ #{value: 0x8000, name:'unused'},
62
+ {value: 0x10000, name:'constructor'},
63
+ {value: 0x20000, name:'declared-synchronized'},
64
+ ]
65
+ # convert access flag to string
66
+ # @return [String]
67
+ def to_s
68
+ ACCESSORS.select{|e| ((e[:value] & @flag) != 0) }.map{|e| e[:name] }.join(' ')
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+