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.
- checksums.yaml +4 -4
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/ruby_apk.iml +51 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +508 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +51 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +73 -0
- data/LICENSE.txt +2 -2
- data/Rakefile +42 -1
- data/VERSION +1 -0
- data/lib/android/apk.rb +207 -0
- data/lib/android/axml_parser.rb +173 -0
- data/lib/android/dex/access_flag.rb +74 -0
- data/lib/android/dex/dex_object.rb +475 -0
- data/lib/android/dex/info.rb +151 -0
- data/lib/android/dex/utils.rb +45 -0
- data/lib/android/dex.rb +92 -0
- data/lib/android/layout.rb +44 -0
- data/lib/android/manifest.rb +249 -0
- data/lib/android/resource.rb +529 -0
- data/lib/android/utils.rb +55 -0
- data/lib/ruby_apk.rb +7 -0
- data/ruby_android.gemspec +103 -17
- data/spec/apk_spec.rb +301 -0
- data/spec/axml_parser_spec.rb +67 -0
- data/spec/data/sample.apk +0 -0
- data/spec/data/sample_AndroidManifest.xml +0 -0
- data/spec/data/sample_classes.dex +0 -0
- data/spec/data/sample_resources.arsc +0 -0
- data/spec/data/sample_resources_utf16.arsc +0 -0
- data/spec/data/str_resources.arsc +0 -0
- data/spec/dex/access_flag_spec.rb +42 -0
- data/spec/dex/dex_object_spec.rb +118 -0
- data/spec/dex/info_spec.rb +121 -0
- data/spec/dex/utils_spec.rb +56 -0
- data/spec/dex_spec.rb +59 -0
- data/spec/layout_spec.rb +27 -0
- data/spec/manifest_spec.rb +221 -0
- data/spec/resource_spec.rb +170 -0
- data/spec/ruby_apk_spec.rb +4 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/utils_spec.rb +90 -0
- metadata +112 -27
- data/.gitignore +0 -14
- data/lib/ruby_android/version.rb +0 -3
- 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 |
|
3
|
-
|
4
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
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
|