ruby_android 0.0.2 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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
+