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