ruby_apk 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/dex_spec.rb ADDED
@@ -0,0 +1,59 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Dex do
4
+ let(:dex_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_classes.dex') }
5
+ let(:dex_bin){ File.open(dex_path, 'rb') {|f| f.read } }
6
+ let(:dex){ Android::Dex.new(dex_bin) }
7
+
8
+
9
+ describe '#initialize' do
10
+ subject { dex }
11
+ context 'with valid dex data' do
12
+ it { should be_instance_of(Android::Dex) }
13
+ end
14
+ context 'with nil data' do
15
+ let(:dex_bin) { nil }
16
+ specify { expect{ subject }.to raise_error }
17
+ end
18
+ end
19
+
20
+ describe '#data' do
21
+ subject { dex.data }
22
+ it { should be_instance_of String }
23
+ specify { subject.encoding.should eq Encoding::ASCII_8BIT }
24
+ end
25
+
26
+ describe '#strings' do
27
+ let(:num_str) { dex.header[:string_ids_size] }
28
+ subject { dex.strings }
29
+ it { should be_instance_of Array }
30
+ it 'should have string_ids_size items' do
31
+ should have(num_str).items
32
+ end
33
+ it "should be the particular string(depends on sample_classes.dex)" do
34
+ subject[0].should eq "%d"
35
+ end
36
+ it "should be the particular string(depends on sample_classes.dex)" do
37
+ subject[1].should eq "<init>"
38
+ end
39
+ it "should be the particular string(depends on sample_classes.dex)" do
40
+ subject[2].should eq "BuildConfig.java"
41
+ end
42
+ end
43
+ describe '#inspect' do
44
+ subject { dex.inspect }
45
+ it { should match(/\A<Android::Dex.*>\Z/m) }
46
+ end
47
+
48
+ describe '#classes' do
49
+ subject { dex.classes }
50
+ let(:num_classes) { dex.header[:class_defs_size] }
51
+ it{ should be_instance_of Array }
52
+ it{ should have(num_classes).items }
53
+ describe 'first item' do
54
+ subject { dex.classes.first }
55
+ it{ should be_instance_of Android::Dex::ClassInfo }
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,179 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Manifest do
4
+ describe Android::Manifest::Component do
5
+ describe "self.valid?" do
6
+ let(:elem) { REXML::Element.new('service') }
7
+ subject { Android::Manifest::Component.valid?(elem) }
8
+ context "with valid component element" do
9
+ it { should be_true }
10
+ end
11
+ context "with invalid component element" do
12
+ let(:elem) { REXML::Element.new('invalid-name') }
13
+ it { should be_false }
14
+ end
15
+ context "when some exception occurs in REXML::Element object" do
16
+ let(:elem) {
17
+ elem = stub(REXML::Element)
18
+ elem.stub(:name).and_raise(StandardError)
19
+ elem
20
+ }
21
+ it { should be_false }
22
+ end
23
+ end
24
+ describe '#metas' do
25
+ subject { Android::Manifest::Component.new(elem).metas }
26
+ context 'with valid component element has 2 meta elements' do
27
+ let(:elem) {
28
+ elem = REXML::Element.new('service')
29
+ elem << REXML::Element.new('meta-data')
30
+ elem << REXML::Element.new('meta-data')
31
+ elem
32
+ }
33
+ it { should have(2).item }
34
+ end
35
+ end
36
+
37
+ describe Android::Manifest::Meta do
38
+ let(:elem) do
39
+ attrs = { 'name' => 'meta name', 'resource' => 'res', 'value' => 'val' }
40
+ elem = stub(REXML::Element, :attributes => attrs)
41
+ elem
42
+ end
43
+ subject { Android::Manifest::Meta.new(elem) }
44
+ its(:name) { should eq 'meta name' }
45
+ its(:resource) { should eq 'res' }
46
+ its(:value) { should eq 'val' }
47
+ end
48
+ end
49
+
50
+ describe Android::Manifest::IntentFilter do
51
+ describe '.parse' do
52
+ subject { Android::Manifest::IntentFilter.parse(elem) }
53
+ context 'assings "action" element' do
54
+ let(:elem) { REXML::Element.new('action') }
55
+ it { should be_instance_of Android::Manifest::IntentFilter::Action }
56
+ end
57
+ context 'assings "category" element' do
58
+ let(:elem) { REXML::Element.new('category') }
59
+ it { should be_instance_of Android::Manifest::IntentFilter::Category }
60
+ end
61
+ context 'assings "data" element' do
62
+ let(:elem) { REXML::Element.new('data') }
63
+ it { should be_instance_of Android::Manifest::IntentFilter::Data }
64
+ end
65
+ context 'assings unknown element' do
66
+ let(:elem) { REXML::Element.new('unknown') }
67
+ it { should be_nil }
68
+ end
69
+ end
70
+ end
71
+
72
+ context "with stub AXMLParser" do
73
+ let(:dummy_xml) {
74
+ xml = REXML::Document.new
75
+ xml << REXML::Element.new('manifest')
76
+ }
77
+ let(:manifest) { Android::Manifest.new('mock data') }
78
+
79
+ before do
80
+ parser = stub(Android::AXMLParser, :parse => dummy_xml)
81
+ Android::AXMLParser.stub(:new).and_return(parser)
82
+ end
83
+
84
+ describe "#use_parmissions" do
85
+ subject { manifest.use_permissions }
86
+ context "with valid 3 parmission elements" do
87
+ before do
88
+ 3.times do |i|
89
+ elem = REXML::Element.new("uses-permission")
90
+ elem.add_attribute 'name', "permission#{i}"
91
+ dummy_xml.root << elem
92
+ end
93
+ end
94
+ it { subject.should have(3).items }
95
+ it "should have permissions" do
96
+ subject.should include("permission0")
97
+ subject.should include("permission1")
98
+ subject.should include("permission2")
99
+ end
100
+ end
101
+ context "with no parmissions" do
102
+ it { should be_empty }
103
+ end
104
+ end
105
+
106
+ describe "#components" do
107
+ subject { manifest.components }
108
+ context "with valid parmission element" do
109
+ before do
110
+ app = REXML::Element.new('application')
111
+ activity = REXML::Element.new('activity')
112
+ app << activity
113
+ dummy_xml.root << app
114
+ end
115
+ it "should have components" do
116
+ subject.should have(1).items
117
+ end
118
+ it "should returns Component object" do
119
+ subject[0].should be_kind_of Android::Manifest::Component
120
+ end
121
+ end
122
+ context "with no components" do
123
+ it { should be_empty }
124
+ end
125
+ end
126
+ end
127
+
128
+ context "with real sample_AndroidManifest.xml data" do
129
+ let(:bin_xml_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_AndroidManifest.xml') }
130
+ let(:bin_xml){ File.open(bin_xml_path, 'rb') {|f| f.read } }
131
+ let(:manifest){ Android::Manifest.new(bin_xml) }
132
+
133
+ describe "#components" do
134
+ subject { manifest.components }
135
+ it { should be_kind_of Array }
136
+ it { subject[0].should be_kind_of Android::Manifest::Component }
137
+ end
138
+ describe "#package_name" do
139
+ subject { manifest.package_name }
140
+ it { should == "example.app.sample" }
141
+ end
142
+ describe "#version_code" do
143
+ subject { manifest.version_code}
144
+ it { should == 101 }
145
+ end
146
+ describe "#version_name" do
147
+ subject { manifest.version_name}
148
+ it { should == "1.0.1-malware2" }
149
+ end
150
+ describe "#min_sdk_ver" do
151
+ subject { manifest.min_sdk_ver}
152
+ it { should == 10 }
153
+ end
154
+ describe "#to_xml" do
155
+ let(:raw_xml){ str = <<EOS
156
+ <manifest xmlns:android='http://schemas.android.com/apk/res/android' android:versionCode='101' android:versionName='1.0.1-malware2' package='example.app.sample'>
157
+ <uses-sdk android:minSdkVersion='10'/>
158
+ <uses-permission android:name='android.permission.INTERNET'/>
159
+ <uses-permission android:name='android.permission.WRITE_EXTERNAL_STORAGE'/>
160
+ <application android:label='@0x7f040001' android:icon='@0x7f020000' android:debuggable='true'>
161
+ <activity android:label='@0x7f040001' android:name='example.app.sample.SampleActivity'>
162
+ <intent-filter>
163
+ <action android:name='android.intent.action.MAIN'/>
164
+ <category android:name='android.intent.category.LAUNCHER'/>
165
+ </intent-filter>
166
+ </activity>
167
+ </application>
168
+ </manifest>
169
+ EOS
170
+ str.strip
171
+ }
172
+
173
+ subject { manifest.to_xml }
174
+ it "should return correct xml string" do
175
+ subject.should == raw_xml
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
3
+
4
+ describe Android::Resource do
5
+ let(:res_data) { File.read(res_path) }
6
+ let(:resource) { Android::Resource.new(res_data) }
7
+
8
+ shared_examples_for 'a valid Android::Resource' do
9
+ subject { resource }
10
+ describe '#initialize' do
11
+ context 'assigns resources.arsc data' do
12
+ it { should be_instance_of Android::Resource }
13
+ end
14
+ end
15
+ its(:package_count) {should eq 1 }
16
+ describe '#strings' do
17
+ subject { resource.strings }
18
+ it { should have(7).items } # depends on sample_resources.arsc
19
+ it { should include 'Sample' }
20
+ it { should include 'Hello World, SampleActivity!' }
21
+ it { should include '日本語リソース' }
22
+ end
23
+ end
24
+ context 'with sample_resources.arsc data' do
25
+ let(:res_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_resources.arsc') }
26
+ it_behaves_like 'a valid Android::Resource'
27
+
28
+ end
29
+ context 'with sample_resources_utf16.arsc data' do
30
+ let(:res_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_resources_utf16.arsc') }
31
+ it_behaves_like 'a valid Android::Resource'
32
+ end
33
+
34
+ describe Android::Resource::ChunkHeader do
35
+ shared_examples_for 'a chunk header' do
36
+ its(:type) { should eq 20 }
37
+ its(:header_size) { should eq 244 }
38
+ its(:size) { should eq 1000 }
39
+ end
40
+ subject { Android::Resource::ChunkHeader.new(data, offset) }
41
+ context 'with no offset' do
42
+ let(:data) { "\x14\x00\xF4\x00\xE8\x03\x00\x00" } # [20, 244, 1000].pack('vvV')
43
+ let(:offset) { 0 }
44
+ it_behaves_like 'a chunk header'
45
+ end
46
+ context 'with 10byte offset' do
47
+ let(:data) { "\x00"*10 + "\x14\x00\xF4\x00\xE8\x03\x00\x00" } # [20, 244, 1000].pack('vvV')
48
+ let(:offset) { 10 }
49
+ it_behaves_like 'a chunk header'
50
+ end
51
+ end
52
+
53
+ describe Android::Resource::ResStringPool do
54
+ describe '.utf8_len' do
55
+ subject { Android::Resource::ResStringPool.utf8_len(data) }
56
+ context 'assigns 0x7F' do
57
+ let(:data) { "\x7f" }
58
+ it { should eq [0x7f, 1] }
59
+ end
60
+ context 'assigns x81x01' do
61
+ let(:data) { "\x81\x01" }
62
+ it { should eq [0x0101, 2] }
63
+ end
64
+ context 'assigns xffxff' do
65
+ let(:data) { "\xff\xff" }
66
+ it { should eq [0x7fff, 2] }
67
+ end
68
+ end
69
+ describe '#utf16_len' do
70
+ subject { Android::Resource::ResStringPool.utf16_len(data) }
71
+ context 'assigns x7fff' do
72
+ let(:data) { "\xff\x7f" }
73
+ it { should eq [0x7fff, 2] }
74
+ end
75
+ context 'assigns x8001,x0001' do
76
+ let(:data) { "\x01\x80\x01\x00" }
77
+ it { should eq [0x10001, 4] }
78
+ end
79
+ context 'assigns xffff,xffff' do
80
+ let(:data) { "\xff\xff\xff\xff" }
81
+ it 'should eq 0x7fff 0xffff' do
82
+ should eq [0x7fffffff, 4]
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "RubyApk" do
4
+ end
@@ -0,0 +1,17 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ add_filter "/spec"
6
+ end
7
+ require 'rspec'
8
+ require 'ruby_apk'
9
+
10
+
11
+ # Requires supporting files with custom matchers and macros, etc,
12
+ # in ./support/ and its subdirectories.
13
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+
17
+ end
@@ -0,0 +1,90 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Utils do
4
+ let(:sample_apk_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
5
+ let(:sample_dex_path) { File.expand_path(File.dirname(__FILE__) + '/data/sample_classes.dex') }
6
+ describe '.apk?' do
7
+ subject { Android::Utils.apk?(apk_path) }
8
+
9
+ context 'assigns apk file path' do
10
+ let(:apk_path) { sample_apk_path }
11
+ it { should be_true }
12
+ end
13
+ context 'assigns nil' do
14
+ let(:apk_path) { nil }
15
+ it { should be_false }
16
+ end
17
+ context 'assigns not exist path' do
18
+ let(:apk_path) { 'hogehoge' }
19
+ it { should be_false }
20
+ end
21
+ context 'assigns not apk file path' do
22
+ let(:apk_path) { __FILE__ }
23
+ it { should be_false }
24
+ end
25
+ end
26
+
27
+ describe '.elf?' do
28
+ subject { Android::Utils.elf?(data) }
29
+ context 'assigns data start with elf magic' do
30
+ let(:data) { "\x7fELF\xff\xff\xff" }
31
+ it { should be_true }
32
+ end
33
+ context 'assigns nil' do
34
+ let(:data) { nil }
35
+ it { should be_false }
36
+ end
37
+ context 'assigns not elf data' do
38
+ let(:data) { "\xff\xff\xff\xff\xff\xff" }
39
+ it { should be_false }
40
+ end
41
+ end
42
+
43
+ describe '.cert?' do
44
+ subject { Android::Utils.cert?(data) }
45
+ context 'assigns data start with x509 magic' do
46
+ let(:data) { "\x30\x82\xff\xff\xff" }
47
+ it { should be_true }
48
+ end
49
+ context 'assigns nil' do
50
+ let(:data) { nil }
51
+ it { should be_false }
52
+ end
53
+ context 'assigns not valid data' do
54
+ let(:data) { "\xff\xff\xff\xff\xff\xff" }
55
+ it { should be_false }
56
+ end
57
+ end
58
+
59
+ describe '.dex?' do
60
+ subject { Android::Utils.dex?(data) }
61
+ context 'assigns dex file data' do
62
+ let(:data) { File.read(sample_dex_path) }
63
+ it { should be_true }
64
+ end
65
+ context 'assigns nil' do
66
+ let(:data) { nil }
67
+ it { should be_false }
68
+ end
69
+ context 'assings not dex data' do
70
+ let(:data) { 'hogehoge' }
71
+ it { should be_false }
72
+ end
73
+ end
74
+ describe '.valid_dex?' do
75
+ subject { Android::Utils.valid_dex?(data) }
76
+ context 'assigns dex file data' do
77
+ let(:data) { File.read(sample_dex_path) }
78
+ it { should be_true }
79
+ end
80
+ context 'assigns nil' do
81
+ let(:data) { nil }
82
+ it { should be_false }
83
+ end
84
+ context 'assings not dex data' do
85
+ let(:data) { 'hogehoge' }
86
+ it { should be_false }
87
+ end
88
+ end
89
+ end
90
+
metadata ADDED
@@ -0,0 +1,198 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_apk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - SecureBrain
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rubyzip
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 2.11.0
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 2.11.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: bundler
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.1.5
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.5
62
+ - !ruby/object:Gem::Dependency
63
+ name: jeweler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.6.4
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.6.4
78
+ - !ruby/object:Gem::Dependency
79
+ name: yard
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: redcarpet
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: simplecov
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: static analysis tool for android apk
127
+ email: info@securebrain.co.jp
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files:
131
+ - LICENSE.txt
132
+ - README.md
133
+ files:
134
+ - .rspec
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - VERSION
141
+ - lib/android/apk.rb
142
+ - lib/android/axml_parser.rb
143
+ - lib/android/dex.rb
144
+ - lib/android/dex/access_flag.rb
145
+ - lib/android/dex/dex_object.rb
146
+ - lib/android/dex/info.rb
147
+ - lib/android/dex/utils.rb
148
+ - lib/android/manifest.rb
149
+ - lib/android/resource.rb
150
+ - lib/android/utils.rb
151
+ - lib/ruby_apk.rb
152
+ - ruby_apk.gemspec
153
+ - spec/apk_spec.rb
154
+ - spec/axml_parser_spec.rb
155
+ - spec/data/sample.apk
156
+ - spec/data/sample_AndroidManifest.xml
157
+ - spec/data/sample_classes.dex
158
+ - spec/data/sample_resources.arsc
159
+ - spec/data/sample_resources_utf16.arsc
160
+ - spec/dex/access_flag_spec.rb
161
+ - spec/dex/dex_object_spec.rb
162
+ - spec/dex/info_spec.rb
163
+ - spec/dex/utils_spec.rb
164
+ - spec/dex_spec.rb
165
+ - spec/manifest_spec.rb
166
+ - spec/resource_spec.rb
167
+ - spec/ruby_apk_spec.rb
168
+ - spec/spec_helper.rb
169
+ - spec/utils_spec.rb
170
+ homepage: http://www.securebrain.co.jp/
171
+ licenses:
172
+ - MIT
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ! '>='
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ segments:
184
+ - 0
185
+ hash: 405895141232042325
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ none: false
188
+ requirements:
189
+ - - ! '>='
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubyforge_project:
194
+ rubygems_version: 1.8.24
195
+ signing_key:
196
+ specification_version: 3
197
+ summary: static analysis tool for android apk
198
+ test_files: []