ruby_android_apk 0.7.7.1

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.
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
@@ -0,0 +1,121 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ shared_context 'with sample_classes.dex', with: :sample_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
+ let(:last_class) { dex.classes.last }
8
+ end
9
+ describe Android::Dex::ClassInfo do
10
+ include_context 'with sample_classes.dex'
11
+ context 'about the last class in Dex#classes with sample_classes.dex' do
12
+ let(:last_class) { dex.classes.last }
13
+ its(:name){ should eq 'Lexample/app/sample/SampleCode;' }
14
+ its(:access_flags){ should be_instance_of Android::Dex::ClassAccessFlag }
15
+ its(:super_class){ should eq 'Ljava/lang/Object;' }
16
+ its(:class_data){ should be_instance_of Android::Dex::DexObject::ClassDataItem }
17
+ its(:class_def){ should be_instance_of Android::Dex::DexObject::ClassDefItem }
18
+ its(:definition) { should eq 'public class Lexample/app/sample/SampleCode; extends Ljava/lang/Object;' }
19
+
20
+ subject { last_class }
21
+ describe '#static_fields' do
22
+ subject { last_class.static_fields }
23
+ it { should have(1).item }
24
+ specify { subject[0].should be_instance_of Android::Dex::FieldInfo }
25
+ end
26
+ describe '#instance_fields' do
27
+ subject { last_class.instance_fields }
28
+ it { should have(1).item }
29
+ specify { subject[0].should be_instance_of Android::Dex::FieldInfo }
30
+ end
31
+ describe '#direct_methods' do
32
+ subject { last_class.direct_methods }
33
+ it { should have(3).items }
34
+ specify { subject[0].should be_instance_of Android::Dex::MethodInfo }
35
+ end
36
+ describe '#virtual_methods' do
37
+ subject { last_class.virtual_methods }
38
+ it { should have(18).items }
39
+ specify { subject[0].should be_instance_of Android::Dex::MethodInfo }
40
+ end
41
+ end
42
+ context 'when class_data_item is nil' do
43
+ let(:mock_cls_def) {
44
+ s = double(Android::Dex::DexObject::ClassDefItem)
45
+ s.stub(:'[]').with(anything()).and_return(0)
46
+ s.stub(:class_data_item).and_return(nil)
47
+ s
48
+ }
49
+ let(:class_info) { Android::Dex::ClassInfo.new(mock_cls_def, nil) }
50
+ describe '#static_fields' do
51
+ subject { class_info.static_fields }
52
+ it { should be_kind_of Array }
53
+ it { should be_empty }
54
+ end
55
+ describe '#instance_fields' do
56
+ subject { class_info.instance_fields }
57
+ it { should be_kind_of Array }
58
+ it { should be_empty }
59
+ end
60
+ describe '#direct_methods' do
61
+ subject { class_info.direct_methods }
62
+ it { should be_kind_of Array }
63
+ it { should be_empty }
64
+ end
65
+ describe '#virtual_methods' do
66
+ subject { class_info.virtual_methods }
67
+ it { should be_kind_of Array }
68
+ it { should be_empty }
69
+ end
70
+ end
71
+ end
72
+
73
+ describe Android::Dex::FieldInfo do
74
+ include_context 'with sample_classes.dex'
75
+ context 'about the first static field of the last class with sample_classes.dex'do
76
+ let(:first_static_field) { last_class.static_fields.first }
77
+ subject { first_static_field }
78
+ its(:name) { should eq 'TAG' }
79
+ its(:type) { should eq 'Ljava/lang/String;' }
80
+ describe '#access_flags' do
81
+ subject { first_static_field.access_flags }
82
+ it { should be_instance_of Android::Dex::ClassAccessFlag }
83
+ specify { subject.to_s.should eq 'private static final' }
84
+ end
85
+ describe '#definition' do
86
+ subject { first_static_field.definition }
87
+ it { should eq 'private static final Ljava/lang/String; TAG' }
88
+ end
89
+ end
90
+ end
91
+
92
+ describe Android::Dex::MethodInfo do
93
+ include_context 'with sample_classes.dex'
94
+ context 'about the first direct method of the last class' do
95
+ let(:first_direct_method) { last_class.direct_methods.first }
96
+ subject { first_direct_method }
97
+ its(:name) { should eq '<init>' }
98
+ end
99
+ context 'about the first virtual method of the last class' do
100
+ let(:first_virtual_method) { last_class.virtual_methods.first }
101
+ subject { first_virtual_method }
102
+ its(:name) { should eq 'processDoWhile' }
103
+ its(:code_item) { should be_instance_of Android::Dex::DexObject::CodeItem }
104
+ describe '#parameters' do
105
+ subject { first_virtual_method.parameters }
106
+ it { should have(1).item }
107
+ it { should include('int') }
108
+ end
109
+ end
110
+ context 'about the 12th virtual method(processTryCatch) of the last class' do
111
+ let(:a_virtual_method) { last_class.virtual_methods[12]}
112
+ subject { a_virtual_method }
113
+ its(:name) { should eq 'processTryCatch' }
114
+ describe '#code_item' do
115
+ subject { a_virtual_method.code_item }
116
+ it { should be_instance_of Android::Dex::DexObject::CodeItem }
117
+ its(:debug_info_item) { should be_instance_of Android::Dex::DexObject::DebugInfoItem }
118
+ end
119
+ end
120
+ end
121
+
@@ -0,0 +1,56 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Android::Dex do
4
+
5
+ describe ".uleb128" do
6
+ # @see http://en.wikipedia.org/wiki/LEB128
7
+ it "[0x00] should be 0" do
8
+ Android::Dex.uleb128("\x00").should == [0,1]
9
+ end
10
+ it "[0x01] should be 1" do
11
+ Android::Dex.uleb128("\x01").should == [1,1]
12
+ end
13
+ it "[0x7f] should be 127" do
14
+ Android::Dex.uleb128("\x7f").should == [127,1]
15
+ end
16
+ it "[0x80,0x7f] should be 16256" do
17
+ Android::Dex.uleb128("\x80\x7f").should == [16256,2]
18
+ end
19
+ it "[0xe5,0x8e,0x26] should be 624485" do
20
+ Android::Dex.uleb128("\xe5\x8e\x26").should == [624485,3]
21
+ end
22
+ end
23
+
24
+ describe ".uleb128p1" do
25
+ it "[0x00] should be -1" do
26
+ Android::Dex.uleb128p1("\x00").should == [-1,1]
27
+ end
28
+ it "[0x01] should be 0" do
29
+ Android::Dex.uleb128p1("\x01").should == [0,1]
30
+ end
31
+ it "[0x7f] should be 126" do
32
+ Android::Dex.uleb128p1("\x7f").should == [126,1]
33
+ end
34
+ it "[0x80,0x7f] should be 16255" do
35
+ Android::Dex.uleb128p1("\x80\x7f").should == [16255,2]
36
+ end
37
+ it "[0xe5,0x8e,0x26] should be 624485" do
38
+ Android::Dex.uleb128("\xe5\x8e\x26").should == [624485,3]
39
+ end
40
+ end
41
+ describe '.sleb128' do
42
+ it "[0x00] should be 0" do
43
+ Android::Dex.sleb128("\x00").should == [0,1]
44
+ end
45
+ it "[0x01] should be 1" do
46
+ Android::Dex.sleb128("\x01").should == [1,1]
47
+ end
48
+ it "[0x7f] should be -1" do
49
+ Android::Dex.sleb128("\x7f").should == [-1,1]
50
+ end
51
+ it "[0x80,0x7f] should be 127" do
52
+ Android::Dex.sleb128("\x80\x7f").should == [-128,2]
53
+ end
54
+ end
55
+ end
56
+
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,41 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Android::Layout do
4
+ context 'with real apk sample file' do
5
+ let(:apk_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample.apk') }
6
+ let(:apk){ Android::Apk.new(apk_path) }
7
+ let(:layouts) { apk.layouts }
8
+ subject { layouts }
9
+ it { should be_a Hash }
10
+ it { should have_key "res/layout/main.xml" }
11
+ it { should have(1).item }
12
+ context 'about first item' do
13
+ subject { layouts['res/layout/main.xml'] }
14
+ it { should be_a Android::Layout }
15
+ describe '#path' do
16
+ it { subject.path.should eq 'res/layout/main.xml' }
17
+ end
18
+ describe '#doc' do
19
+ it { subject.doc.should be_a REXML::Document }
20
+ end
21
+ describe '#to_xml' do
22
+ it { subject.to_xml.should be_a String }
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'with real new apk sample file' do
28
+ let(:apk_path){ File.expand_path(File.dirname(__FILE__) + '/data/sample_new.apk') }
29
+ let(:apk){ Android::Apk.new(apk_path) }
30
+ let(:layouts) { apk.layouts }
31
+ subject { layouts }
32
+ it { should be_a Hash }
33
+ it { should have_key "res/layout/activity_main.xml" }
34
+ it { should have(1).item }
35
+ context 'about first item' do
36
+ subject { layouts['res/layout/activity_main.xml'] }
37
+ it { should be_a Android::Layout }
38
+ end
39
+ end
40
+ end
41
+