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/ruby_android.gemspec CHANGED
@@ -1,21 +1,107 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: ruby_android 0.7.2 ruby lib
1
6
 
2
- Gem::Specification.new do |spec|
3
- spec.name = "ruby_android"
4
- spec.version = '0.0.2'
5
- spec.authors = ["Michal Tajchert"]
6
- spec.email = ["thetajchert@gmail.com"]
7
- spec.homepage = 'https://github.com/tajchert/ruby_android'
8
- spec.summary = 'static analysis tool for android apk'
9
- spec.description = 'copy of update ruby_apk'
10
- spec.license = "MIT"
7
+ Gem::Specification.new do |s|
8
+ s.name = "ruby_android"
9
+ s.version = "0.7.2"
11
10
 
12
- spec.files = `git ls-files -z`.split("\x0")
13
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
15
- spec.require_paths = ["lib"]
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Michal Tajchert", "SecureBrain"]
14
+ s.date = "2014-08-29"
15
+ s.description = "static analysis tool for android apk"
16
+ s.email = "thetajchert@gmail.com"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".idea/.name",
23
+ ".idea/.rakeTasks",
24
+ ".idea/encodings.xml",
25
+ ".idea/misc.xml",
26
+ ".idea/modules.xml",
27
+ ".idea/ruby_apk.iml",
28
+ ".idea/scopes/scope_settings.xml",
29
+ ".idea/vcs.xml",
30
+ ".idea/workspace.xml",
31
+ ".travis.yml",
32
+ "CHANGELOG.md",
33
+ "Gemfile",
34
+ "Gemfile.lock",
35
+ "LICENSE.txt",
36
+ "README.md",
37
+ "Rakefile",
38
+ "VERSION",
39
+ "lib/android/apk.rb",
40
+ "lib/android/axml_parser.rb",
41
+ "lib/android/dex.rb",
42
+ "lib/android/dex/access_flag.rb",
43
+ "lib/android/dex/dex_object.rb",
44
+ "lib/android/dex/info.rb",
45
+ "lib/android/dex/utils.rb",
46
+ "lib/android/layout.rb",
47
+ "lib/android/manifest.rb",
48
+ "lib/android/resource.rb",
49
+ "lib/android/utils.rb",
50
+ "lib/ruby_apk.rb",
51
+ "ruby_android.gemspec",
52
+ "spec/apk_spec.rb",
53
+ "spec/axml_parser_spec.rb",
54
+ "spec/data/sample.apk",
55
+ "spec/data/sample_AndroidManifest.xml",
56
+ "spec/data/sample_classes.dex",
57
+ "spec/data/sample_resources.arsc",
58
+ "spec/data/sample_resources_utf16.arsc",
59
+ "spec/data/str_resources.arsc",
60
+ "spec/dex/access_flag_spec.rb",
61
+ "spec/dex/dex_object_spec.rb",
62
+ "spec/dex/info_spec.rb",
63
+ "spec/dex/utils_spec.rb",
64
+ "spec/dex_spec.rb",
65
+ "spec/layout_spec.rb",
66
+ "spec/manifest_spec.rb",
67
+ "spec/resource_spec.rb",
68
+ "spec/ruby_apk_spec.rb",
69
+ "spec/spec_helper.rb",
70
+ "spec/utils_spec.rb"
71
+ ]
72
+ s.homepage = "https://github.com/tajchert/ruby_apk"
73
+ s.licenses = ["MIT"]
74
+ s.rubygems_version = "2.4.1"
75
+ s.summary = "static analysis tool for android apk"
16
76
 
17
- spec.add_development_dependency "bundler", '~> 1.7'
18
- spec.add_development_dependency "rake", '~> 10.0'
19
- spec.add_runtime_dependency "rubyzip", '~> 1.1'
20
- spec.add_development_dependency "rspec", '~> 2.11'
77
+ if s.respond_to? :specification_version then
78
+ s.specification_version = 4
79
+
80
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
+ s.add_runtime_dependency(%q<rubyzip>, [">= 1.1.6"])
82
+ s.add_development_dependency(%q<rspec>, ["~> 2.11.0"])
83
+ s.add_development_dependency(%q<bundler>, [">= 1.3.0"])
84
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.7"])
85
+ s.add_development_dependency(%q<yard>, [">= 0"])
86
+ s.add_development_dependency(%q<redcarpet>, [">= 0"])
87
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
88
+ else
89
+ s.add_dependency(%q<rubyzip>, [">= 1.1.6"])
90
+ s.add_dependency(%q<rspec>, ["~> 2.11.0"])
91
+ s.add_dependency(%q<bundler>, [">= 1.3.0"])
92
+ s.add_dependency(%q<jeweler>, ["~> 1.8.7"])
93
+ s.add_dependency(%q<yard>, [">= 0"])
94
+ s.add_dependency(%q<redcarpet>, [">= 0"])
95
+ s.add_dependency(%q<simplecov>, [">= 0"])
96
+ end
97
+ else
98
+ s.add_dependency(%q<rubyzip>, [">= 1.1.6"])
99
+ s.add_dependency(%q<rspec>, ["~> 2.11.0"])
100
+ s.add_dependency(%q<bundler>, [">= 1.3.0"])
101
+ s.add_dependency(%q<jeweler>, ["~> 1.8.7"])
102
+ s.add_dependency(%q<yard>, [">= 0"])
103
+ s.add_dependency(%q<redcarpet>, [">= 0"])
104
+ s.add_dependency(%q<simplecov>, [">= 0"])
105
+ end
21
106
  end
107
+
data/spec/apk_spec.rb ADDED
@@ -0,0 +1,301 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'tempfile'
3
+ require 'zip'
4
+ require 'digest/sha1'
5
+ require 'digest/sha2'
6
+ require 'digest/md5'
7
+
8
+ class TempApk
9
+ attr_reader :path
10
+ def initialize
11
+ @tmp = Tempfile.open('apk_spec')
12
+ @path = @tmp.path
13
+ @tmp.close! # delete file
14
+ append("AndroidManifest.xml", "hogehoge")
15
+ append("resources.arsc", "hogehoge")
16
+ end
17
+ def destroy!
18
+ File.unlink(@path) if File.exist? @path
19
+ end
20
+ def append(entry_name, data)
21
+ Zip::File.open(@path, Zip::File::CREATE) { |zip|
22
+ zip.get_output_stream(entry_name) {|f| f.write data }
23
+ }
24
+ end
25
+ def remove(entry_name)
26
+ Zip::File.open(@path, Zip::File::CREATE) { |zip|
27
+ zip.remove(entry_name)
28
+ }
29
+ end
30
+ end
31
+
32
+ describe Android::Apk do
33
+ before do
34
+ $stderr.reopen('/dev/null','w')
35
+ end
36
+ let(:tmp_apk) { TempApk.new }
37
+ let(:tmp_path) { tmp_apk.path }
38
+ let(:apk) { Android::Apk.new(tmp_path) }
39
+ subject { apk }
40
+
41
+ after do
42
+ tmp_apk.destroy!
43
+ end
44
+
45
+ describe "#initialize" do
46
+ let(:path) { tmp_path }
47
+ subject { Android::Apk.new(path) }
48
+ context "with not exist path" do
49
+ let(:path) { "not exist path" }
50
+ it { expect{ subject }.to raise_error Android::NotFoundError }
51
+ end
52
+ context "with not zip file path" do
53
+ let(:path) { __FILE__ } # not zip file
54
+ it { expect{ subject }.to raise_error Android::NotApkFileError }
55
+ end
56
+ context "with zip(and non apk) file" do
57
+ before do
58
+ tmp_apk.append('hoge.txt', 'hogehoge')
59
+ tmp_apk.remove('AndroidManifest.xml')
60
+ end
61
+ it { expect{ subject }.to raise_error Android::NotApkFileError }
62
+ end
63
+ context "with zip includes AndroidManifest.xml" do
64
+ it { should be_a_instance_of Android::Apk }
65
+ end
66
+ end
67
+
68
+ describe "#path" do
69
+ subject { apk.path }
70
+ it "should equals initialized path" do
71
+ should == tmp_path
72
+ end
73
+ end
74
+
75
+ describe "#manifest" do
76
+ subject { apk.manifest }
77
+
78
+ context "when Manifest parse is succeeded." do
79
+ let(:mock_mani) { mock(Android::Manifest) }
80
+
81
+ before do
82
+ end
83
+ it "should return manifest object" do
84
+ Android::Manifest.should_receive(:new).and_return(mock_mani)
85
+ subject.should == mock_mani
86
+ end
87
+ end
88
+
89
+ context "when Manifest parse is failed" do
90
+ it 'should return nil' do
91
+ Android::Manifest.should_receive(:new).and_raise(Android::AXMLParser::ReadError)
92
+ subject.should be_nil
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "#dex" do
98
+ let(:mock_dex) { mock(Android::Dex) }
99
+ subject { apk.dex }
100
+ context "when there is no dex file" do
101
+ it { should be_nil }
102
+ end
103
+ context "when invalid dex file" do
104
+ before do
105
+ tmp_apk.append("classes.dex", "invalid dex")
106
+ end
107
+ it { should be_nil }
108
+ end
109
+ context "with mock classes.dex file" do
110
+ before do
111
+ tmp_apk.append("classes.dex", "mock data")
112
+ end
113
+ it "should return mock value" do
114
+ Android::Dex.should_receive(:new).with("mock data").and_return(mock_dex)
115
+ subject.should == mock_dex
116
+ end
117
+ end
118
+ context "with real classes.dex file" do
119
+ before do
120
+ dex_path = File.expand_path(File.dirname(__FILE__) + '/data/sample_classes.dex')
121
+ tmp_apk.append("classes.dex", File.open(dex_path, "rb") {|f| f.read })
122
+ end
123
+ it { should be_instance_of Android::Dex }
124
+ end
125
+ end
126
+
127
+ its(:bindata) { should be_instance_of String }
128
+ describe '#bindata' do
129
+ specify 'encoding should be ASCII-8BIT' do
130
+ subject.bindata.encoding.should eq Encoding::ASCII_8BIT
131
+ end
132
+ end
133
+
134
+ describe '#resource' do
135
+ let(:mock_rsc) { mock(Android::Resource) }
136
+ subject { apk.resource }
137
+ it "should return manifest object" do
138
+ Android::Resource.should_receive(:new).and_return(mock_rsc)
139
+ subject.should == mock_rsc
140
+ end
141
+ end
142
+
143
+ describe "#size" do
144
+ subject { apk.size }
145
+ it "should return apk file size" do
146
+ should == File.size(tmp_path)
147
+ end
148
+ end
149
+
150
+ describe "#digest" do
151
+ let(:data) { File.open(tmp_apk.path, 'rb'){|f| f.read } }
152
+ subject { apk.digest(type) }
153
+ context "when type is sha1" do
154
+ let(:type) { :sha1 }
155
+ it "should return sha1 digest" do
156
+ should eq Digest::SHA1.hexdigest(data)
157
+ end
158
+ end
159
+ context "when type is sha256" do
160
+ let(:type) { :sha256 }
161
+ it "should return sha256 digest" do
162
+ should == Digest::SHA256.hexdigest(data)
163
+ end
164
+ end
165
+ context "when type is md5" do
166
+ let(:type) { :md5 }
167
+ it "should return md5 digest" do
168
+ should == Digest::MD5.hexdigest(data)
169
+ end
170
+ end
171
+ context "when type is unkown symbol" do
172
+ let(:type) { :unknown }
173
+ it do
174
+ expect { subject }.to raise_error(ArgumentError)
175
+ end
176
+ end
177
+ context "when type is not symbol(String: 'sha1')" do
178
+ let(:type) { 'sha1' }
179
+ it { expect { subject }.to raise_error(ArgumentError) }
180
+ end
181
+ end
182
+
183
+ describe '#time' do
184
+ subject { apk.time }
185
+ it { should be_kind_of Time }
186
+ end
187
+
188
+ describe "#each_file" do
189
+ before do
190
+ tmp_apk.append("hoge.txt", "aaaaaaa")
191
+ end
192
+ it { expect { |b| apk.each_file(&b) }.to yield_successive_args(Array, Array, Array) }
193
+ let(:each_file_result ) {
194
+ result = []
195
+ apk.each_file do |name, data|
196
+ result << [name, data]
197
+ end
198
+ result
199
+ }
200
+
201
+ it "should invoke block with all file" do
202
+ each_file_result.should have(3).items
203
+ each_file_result.should include(['AndroidManifest.xml', 'hogehoge'])
204
+ each_file_result.should include(['hoge.txt','aaaaaaa'])
205
+ end
206
+ end
207
+
208
+ describe '#file' do
209
+ let(:data) { 'aaaaaaaaaaaaaaaaaaaaaaaaaaa' }
210
+ let(:path) { 'hoge.txt' }
211
+ subject { apk.file(path) }
212
+
213
+ before do
214
+ tmp_apk.append('hoge.txt', data)
215
+ end
216
+ context 'assigns exist path' do
217
+ it 'should equal file data' do
218
+ should eq data
219
+ end
220
+ end
221
+ context 'assigns not exist path' do
222
+ let(:path) { 'not_exist_path.txt' }
223
+ it { expect { subject }.to raise_error(Android::NotFoundError) }
224
+ end
225
+ end
226
+
227
+ describe '#each_entry' do
228
+ before do
229
+ tmp_apk.append("hoge.txt", "aaaaaaa")
230
+ end
231
+ it { expect { |b| apk.each_entry(&b) }.to yield_successive_args(Zip::Entry, Zip::Entry, Zip::Entry) }
232
+ end
233
+
234
+ describe '#entry' do
235
+ subject { apk.entry(entry_name) }
236
+ context 'assigns exist entry' do
237
+ let(:entry_name) { 'AndroidManifest.xml' }
238
+ it { should be_instance_of Zip::Entry }
239
+ end
240
+ context 'assigns not exist entry name' do
241
+ let(:entry_name) { 'not_exist_path' }
242
+ it { expect{ subject }.to raise_error(Android::NotFoundError) }
243
+ end
244
+ end
245
+
246
+ describe "#find" do
247
+ before do
248
+ tmp_apk.append("hoge.txt", "aaaaaaa")
249
+ end
250
+ it "should return matched array" do
251
+ array = apk.find do |name, data|
252
+ name == "hoge.txt"
253
+ end
254
+ array.should be_instance_of Array
255
+ array.should have(1).item
256
+ array[0] == "hoge.txt" # returns filename
257
+ end
258
+ context "when no entry is matched" do
259
+ it "should return emtpy array" do
260
+ array = apk.find do |name, dota|
261
+ false # nothing matched
262
+ end
263
+ array.should be_instance_of Array
264
+ array.should be_empty
265
+ end
266
+ end
267
+ end
268
+
269
+ describe "#icon" do
270
+ context "with real apk file" do
271
+ let(:tmp_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
272
+ subject { apk.icon }
273
+ it { should be_a Hash }
274
+ it { should have(3).items }
275
+ it { subject.keys.should =~ ["res/drawable-hdpi/ic_launcher.png", "res/drawable-ldpi/ic_launcher.png", "res/drawable-mdpi/ic_launcher.png"]
276
+ }
277
+ end
278
+ end
279
+
280
+ describe '#signs' do
281
+ context 'with sampe apk file' do
282
+ let(:tmp_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
283
+ subject { apk.signs }
284
+ it { should be_a Hash }
285
+ it { should have(1).item }
286
+ it { should have_key('META-INF/CERT.RSA') }
287
+ it { subject['META-INF/CERT.RSA'].should be_a OpenSSL::PKCS7 }
288
+ end
289
+ end
290
+
291
+ describe '#certficates' do
292
+ context 'with sampe apk file' do
293
+ let(:tmp_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
294
+ subject { apk.certificates }
295
+ it { should be_a Hash }
296
+ it { should have(1).item }
297
+ it { should have_key('META-INF/CERT.RSA') }
298
+ it { subject['META-INF/CERT.RSA'].should be_a OpenSSL::X509::Certificate }
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Android::AXMLParser do
5
+ let(:bin_xml_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_AndroidManifest.xml') }
6
+ let(:bin_xml){ File.open(bin_xml_path, 'rb') {|f| f.read } }
7
+ let(:axmlparser){ Android::AXMLParser.new(bin_xml) }
8
+
9
+ describe "#parse" do
10
+
11
+ subject { axmlparser.parse }
12
+ context 'with sample_AndroidManifest.xml' do
13
+ it { should be_instance_of(REXML::Document) }
14
+ specify 'root element should be <manifest> element' do
15
+ subject.root.name.should eq 'manifest'
16
+ end
17
+ specify 'should have 2 <uses-permission> elements' do
18
+ subject.get_elements('/manifest/uses-permission').should have(2).items
19
+ end
20
+ end
21
+
22
+ context 'with nil data as binary xml' do
23
+ let(:bin_xml) { nil }
24
+ specify { expect{ subject }.to raise_error }
25
+ end
26
+
27
+ end
28
+
29
+ describe "#strings" do
30
+ context 'with sample_AndroidManifest.xml' do
31
+ subject { axmlparser.strings }
32
+ before do
33
+ axmlparser.parse
34
+ end
35
+ it { should be_instance_of(Array) }
36
+
37
+ # ugh!! the below test cases depend on sample_AndroidManifest.xml
38
+ it { should have(26).items} # in sample manifest.
39
+ it { should include("versionCode") }
40
+ it { should include("versionName") }
41
+ it { should include("minSdkVersion") }
42
+ it { should include("package") }
43
+ it { should include("manifest") }
44
+ end
45
+ end
46
+
47
+ describe '#convert_value' do
48
+ let(:axmlparser){ Android::AXMLParser.new('') }
49
+ subject { axmlparser.convert_value(str_id, flags, val) }
50
+ context 'when parsing boolean attribute' do
51
+ let(:str_id) { 0xFFFFFFFF }
52
+ let(:flags) { 0x12000008 }
53
+ context 'and value is 0x01' do
54
+ let(:val) { 0x01 }
55
+ it { should be_true }
56
+ end
57
+ context 'and value is 0xFFFFFFF' do
58
+ let(:val) { 0xFFFFFFFF }
59
+ it { should be_true }
60
+ end
61
+ context 'and value is 0x00' do
62
+ let(:val) { 0x00 }
63
+ it { should be_false }
64
+ end
65
+ end
66
+ end
67
+ end
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Android::Dex::AccessFlag do
4
+ let(:flag) { 0x01 }
5
+ subject { Android::Dex::AccessFlag.new(flag) }
6
+ its(:flag) { should eq flag }
7
+ end
8
+
9
+ describe Android::Dex::ClassAccessFlag do
10
+ let(:accessor) { Android::Dex::ClassAccessFlag.new(flags) }
11
+
12
+ subject { accessor.to_s }
13
+ context 'flags are 0x19(public static final)' do
14
+ let(:flags) { 0x19 }
15
+ it { should eq 'public static final' }
16
+ end
17
+ context 'flags are 0xc0(volatile transient)' do
18
+ let(:flags) { 0xc0 }
19
+ it { should eq 'volatile transient' }
20
+ end
21
+ context 'flags are 0x22(private synchronized)' do
22
+ let(:flags) { 0x22 }
23
+ it { should eq 'private synchronized' }
24
+ end
25
+ end
26
+
27
+ describe Android::Dex::MethodAccessFlag do
28
+ let(:accessor) { Android::Dex::MethodAccessFlag.new(flags) }
29
+ subject { accessor.to_s }
30
+ context 'flags are 0x19(public static final)' do
31
+ let(:flags) { 0x19 }
32
+ it { should eq 'public static final' }
33
+ end
34
+ context 'flags are 0xc0(bridge varargs)' do
35
+ let(:flags) { 0xc0 }
36
+ it { should eq 'bridge varargs' }
37
+ end
38
+ context 'flags are 0x22(private synchronized)' do
39
+ let(:flags) { 0x22 }
40
+ it { should eq 'private synchronized' }
41
+ end
42
+ end
@@ -0,0 +1,118 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Android::Dex do
4
+ describe Android::Dex::DexObject::Header do
5
+ let(:header_sample) {
6
+ sample =
7
+ "\x64\x65\x78\x0A\x30\x33\x35\x00\x3F\x14\x98\x2C\x25\x77\x9B\x8D" +
8
+ "\x7C\xF0\x0B\xFA\x4D\x7B\x03\xAD\x4C\x15\xBC\x31\x4F\xD3\x4B\x71" +
9
+ "\x58\x18\x00\x00\x70\x00\x00\x00\x78\x56\x34\x12\x00\x00\x00\x00" +
10
+ "\x00\x00\x00\x00\x88\x17\x00\x00\x7A\x00\x00\x00\x70\x00\x00\x00" +
11
+ "\x23\x00\x00\x00\x58\x02\x00\x00\x0E\x00\x00\x00\xE4\x02\x00\x00" +
12
+ "\x10\x00\x00\x00\x8C\x03\x00\x00\x2C\x00\x00\x00\x0C\x04\x00\x00" +
13
+ "\x0A\x00\x00\x00\x6C\x05\x00\x00\xAC\x11\x00\x00\xAC\x06\x00\x00"
14
+ sample.force_encoding(Encoding::ASCII_8BIT)
15
+ }
16
+ let(:header) { Android::Dex::DexObject::Header.new(header_sample) }
17
+ describe "#symbols" do
18
+ subject { header.symbols }
19
+ it { should be_kind_of(Array) }
20
+ it { should have(23).items }
21
+ it { should include(:magic) }
22
+ it { should include(:checksum) }
23
+ it { should include(:signature) }
24
+ it { should include(:file_size) }
25
+ it { should include(:header_size) }
26
+ it { should include(:endian_tag) }
27
+ it { should include(:link_size) }
28
+ it { should include(:link_off) }
29
+ it { should include(:map_off) }
30
+ it { should include(:string_ids_size) }
31
+ it { should include(:string_ids_off) }
32
+ it { should include(:type_ids_size) }
33
+ it { should include(:type_ids_off) }
34
+ it { should include(:proto_ids_size) }
35
+ it { should include(:proto_ids_off) }
36
+ it { should include(:field_ids_size) }
37
+ it { should include(:field_ids_off) }
38
+ it { should include(:method_ids_size) }
39
+ it { should include(:method_ids_off) }
40
+ it { should include(:class_defs_size) }
41
+ it { should include(:class_defs_off) }
42
+ it { should include(:data_size) }
43
+ it { should include(:data_off) }
44
+ end
45
+
46
+ describe "#[]" do
47
+ subject { header }
48
+ it ':magic should be "dex\n035\0"' do
49
+ subject[:magic].should == "dex\n035\0"
50
+ end
51
+ it ":checksum should be 748164159(this value depends on sample_classes.dex)" do
52
+ subject[:checksum].should == 748164159
53
+ end
54
+ it ":signature should be 20byte string" do
55
+ subject[:signature].should be_kind_of String
56
+ subject[:signature].length == 20
57
+ end
58
+ it ":file_size should be classes.dex file size" do
59
+ subject[:file_size].should == 6232
60
+ end
61
+ it ":header_size should be 0x70" do
62
+ subject[:header_size].should == 0x70
63
+ end
64
+ it "should have integer params" do
65
+ subject[:header_size].should == 0x70
66
+ end
67
+ context "with int symbols" do
68
+ before do
69
+ @params = [
70
+ :link_size,
71
+ :link_off,
72
+ :map_off,
73
+ :string_ids_size,
74
+ :string_ids_off,
75
+ :type_ids_size,
76
+ :type_ids_off,
77
+ :proto_ids_size,
78
+ :proto_ids_off,
79
+ :field_ids_size,
80
+ :field_ids_off,
81
+ :method_ids_size,
82
+ :method_ids_off,
83
+ :class_defs_size,
84
+ :class_defs_off,
85
+ :data_size,
86
+ :data_off,
87
+ ]
88
+ end
89
+ it "should have integer value" do
90
+ @params.each do |sym|
91
+ subject[sym].should be_kind_of Integer
92
+ end
93
+ end
94
+ end
95
+ context "with unkown params" do
96
+ it { subject[:unkown].should be_nil }
97
+ end
98
+ end
99
+
100
+ describe "#inspect" do
101
+ subject { header.inspect }
102
+ it { should match(/\A<Android::Dex::DexObject::Header.*>\Z/m) }
103
+ end
104
+ end
105
+
106
+ describe Android::Dex::DexObject::StringDataItem do
107
+ let(:string_data_item_sample) {
108
+ sample = "\x0b\x61\x62\x63\xc0\x80\xc8\x85\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xed\xa0\x81\xed\xb0\x80\xc0\x80"
109
+ sample.force_encoding(Encoding::ASCII_8BIT)
110
+ }
111
+ let(:string_data_item) { Android::Dex::DexObject::StringDataItem.new(string_data_item_sample, 0) }
112
+ describe "#to_s" do
113
+ subject { string_data_item.to_s }
114
+ it { should == "abc\u{205}\u{3042}\u{3044}\u{3046}\u{10400}" }
115
+ end
116
+ end
117
+
118
+ end