ruby_apk 0.4.0

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.
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: []