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/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