dex-oracle 1.0.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 +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.txt +21 -0
- data/README.md +102 -0
- data/bin/dex-oracle +98 -0
- data/dex-oracle.gemspec +43 -0
- data/driver/build.gradle +52 -0
- data/driver/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/driver/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/driver/gradlew +160 -0
- data/driver/gradlew.bat +90 -0
- data/driver/src/main/java/org/cf/oracle/Driver.java +134 -0
- data/driver/src/main/java/org/cf/oracle/FileUtils.java +35 -0
- data/driver/src/main/java/org/cf/oracle/StackSpoofer.java +42 -0
- data/driver/src/main/java/org/cf/oracle/options/InvocationTarget.java +40 -0
- data/driver/src/main/java/org/cf/oracle/options/TargetParser.java +121 -0
- data/lib/dex-oracle/driver.rb +255 -0
- data/lib/dex-oracle/logging.rb +32 -0
- data/lib/dex-oracle/plugin.rb +87 -0
- data/lib/dex-oracle/plugins/string_decryptor.rb +59 -0
- data/lib/dex-oracle/plugins/undexguard.rb +155 -0
- data/lib/dex-oracle/plugins/unreflector.rb +85 -0
- data/lib/dex-oracle/resources.rb +13 -0
- data/lib/dex-oracle/smali_field.rb +21 -0
- data/lib/dex-oracle/smali_file.rb +64 -0
- data/lib/dex-oracle/smali_input.rb +81 -0
- data/lib/dex-oracle/smali_method.rb +33 -0
- data/lib/dex-oracle/utility.rb +37 -0
- data/lib/dex-oracle/version.rb +3 -0
- data/lib/oracle.rb +61 -0
- data/res/driver.dex +0 -0
- data/res/dx.jar +0 -0
- data/spec/data/helloworld.apk +0 -0
- data/spec/data/helloworld.dex +0 -0
- data/spec/data/plugins/bytes_decrypt.smali +18 -0
- data/spec/data/plugins/class_forname.smali +14 -0
- data/spec/data/plugins/multi_bytes_decrypt.smali +28 -0
- data/spec/data/plugins/string_decrypt.smali +14 -0
- data/spec/data/plugins/string_lookup_1int.smali +14 -0
- data/spec/data/plugins/string_lookup_3int.smali +18 -0
- data/spec/data/smali/helloworld.smali +17 -0
- data/spec/dex-oracle/driver_spec.rb +82 -0
- data/spec/dex-oracle/plugins/string_decryptor_spec.rb +25 -0
- data/spec/dex-oracle/plugins/undexguard_spec.rb +69 -0
- data/spec/dex-oracle/plugins/unreflector_spec.rb +29 -0
- data/spec/dex-oracle/smali_field_spec.rb +15 -0
- data/spec/dex-oracle/smali_file_spec.rb +41 -0
- data/spec/dex-oracle/smali_input_spec.rb +90 -0
- data/spec/dex-oracle/smali_method_spec.rb +19 -0
- data/spec/spec_helper.rb +9 -0
- data/update_driver +5 -0
- metadata +195 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
.class public Lorg/cf/MultiBytesDecrypt;
|
2
|
+
.super Ljava/lang/Object;
|
3
|
+
|
4
|
+
.method public static doStuff()V
|
5
|
+
.locals 3
|
6
|
+
|
7
|
+
const-string v0, "string1"
|
8
|
+
|
9
|
+
new-instance v1, Ljava/lang/String;
|
10
|
+
|
11
|
+
invoke-static {v0}, Lorg/cf/MultiBytesDecrypt;->doThing1(Ljava/lang/String;)[B
|
12
|
+
|
13
|
+
move-result-object v2
|
14
|
+
|
15
|
+
const-string v3, "string2"
|
16
|
+
|
17
|
+
invoke-static {v2, v3}, Lorg/cf/MultiBytesDecrypt;->doThing2([BLjava/lang/String;)[B
|
18
|
+
|
19
|
+
move-result-object v2
|
20
|
+
|
21
|
+
invoke-static {v2}, Lorg/cf/MultiBytesDecrypt;->doThing3([B)[B
|
22
|
+
|
23
|
+
move-result-object v2
|
24
|
+
|
25
|
+
invoke-direct {v1, v2}, Ljava/lang/String;-><init>([B)V
|
26
|
+
|
27
|
+
return-void
|
28
|
+
.end method
|
@@ -0,0 +1,14 @@
|
|
1
|
+
.class public Lorg/cf/StringDecrypt;
|
2
|
+
.super Ljava/lang/Object;
|
3
|
+
|
4
|
+
.method public static doStuff()V
|
5
|
+
.locals 1
|
6
|
+
|
7
|
+
const-string v0, "encrypted"
|
8
|
+
|
9
|
+
invoke-static {v0}, Lorg/cf/StringDecrypt;->decrypt(Ljava/lang/String;)Ljava/lang/String;
|
10
|
+
|
11
|
+
move-result-object v0
|
12
|
+
|
13
|
+
return-void
|
14
|
+
.end method
|
@@ -0,0 +1,14 @@
|
|
1
|
+
.class public Lorg/cf/StringLookup;
|
2
|
+
.super Ljava/lang/Object;
|
3
|
+
|
4
|
+
.method public static doStuff()V
|
5
|
+
.locals 1
|
6
|
+
|
7
|
+
const/4 v0, 0x0
|
8
|
+
|
9
|
+
invoke-static {v0}, Lorg/cf/StringLookup;->lookup(I)Ljava/lang/String;
|
10
|
+
|
11
|
+
move-result-object v0
|
12
|
+
|
13
|
+
return-void
|
14
|
+
.end method
|
@@ -0,0 +1,18 @@
|
|
1
|
+
.class public Lorg/cf/StringLookup;
|
2
|
+
.super Ljava/lang/Object;
|
3
|
+
|
4
|
+
.method public static doStuff()V
|
5
|
+
.locals 3
|
6
|
+
|
7
|
+
const/4 v0, 0x0
|
8
|
+
|
9
|
+
const/4 v1, 0x1
|
10
|
+
|
11
|
+
const/4 v2, 0x2
|
12
|
+
|
13
|
+
invoke-static {v0, v1, v2}, Lorg/cf/StringLookup;->lookup(III)Ljava/lang/String;
|
14
|
+
|
15
|
+
move-result-object v0
|
16
|
+
|
17
|
+
return-void
|
18
|
+
.end method
|
@@ -0,0 +1,17 @@
|
|
1
|
+
.class public LHelloWorld; # COMMENT;
|
2
|
+
.super Ljava/lang/Object; # YEAH ;
|
3
|
+
.implements Lsome/Interface1;
|
4
|
+
.implements Lsome/Interface2;
|
5
|
+
|
6
|
+
.field public static final someField:Z
|
7
|
+
|
8
|
+
.method public static main([Ljava/lang/String;)V
|
9
|
+
.locals 2
|
10
|
+
|
11
|
+
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
|
12
|
+
const-string v1, "hello,world!"
|
13
|
+
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
14
|
+
|
15
|
+
return-void
|
16
|
+
.end method
|
17
|
+
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Driver do
|
4
|
+
let(:temp_file) { instance_double('Tempfile') }
|
5
|
+
let(:class_name) { 'some/Klazz' }
|
6
|
+
let(:method_signature) { 'run(III)V' }
|
7
|
+
let(:args) { [1, 2, 3] }
|
8
|
+
let(:batch_id) { '8ea0a5c705617449899c85cec2435356e8be83d6829e12ff109ab0c44c4156c6' }
|
9
|
+
let(:batch_item) { { className: 'some.Klazz', methodName: 'run', arguments: %w(I:1 I:2 I:3), id: batch_id } }
|
10
|
+
let(:driver) do
|
11
|
+
allow(temp_file).to receive(:path).and_return('/fake/tmp/file')
|
12
|
+
allow(temp_file).to receive(:unlink)
|
13
|
+
allow(temp_file).to receive(:close)
|
14
|
+
allow(temp_file).to receive(:flush)
|
15
|
+
allow(temp_file).to receive(:<<)
|
16
|
+
allow(Tempfile).to receive(:new).and_return(temp_file)
|
17
|
+
allow(File).to receive(:open).and_yield(temp_file)
|
18
|
+
allow(File).to receive(:read)
|
19
|
+
allow(JSON).to receive(:parse)
|
20
|
+
Driver.new(device_id)
|
21
|
+
end
|
22
|
+
let(:driver_stub) { 'export CLASSPATH=/data/local/od.zip; app_process /system/bin org.cf.oracle.Driver' }
|
23
|
+
|
24
|
+
describe '#make_target' do
|
25
|
+
let(:device_id) { '' }
|
26
|
+
let(:make_target) { driver.make_target(class_name, method_signature, *args) }
|
27
|
+
|
28
|
+
subject { make_target }
|
29
|
+
it { should eq batch_item }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#run_batch' do
|
33
|
+
let(:device_id) { '' }
|
34
|
+
let(:batch) { [batch_item] }
|
35
|
+
let(:run_batch) { driver.run_batch(batch) }
|
36
|
+
|
37
|
+
subject { run_batch }
|
38
|
+
it do
|
39
|
+
expect(temp_file).to receive(:<<).with(batch.to_json).ordered
|
40
|
+
expect(driver).to receive(:adb).with("push #{temp_file.path} /data/local/od-targets.json")
|
41
|
+
expect(driver).to receive(:drive).with("#{driver_stub} @/data/local/od-targets.json", true)
|
42
|
+
allow(JSON).to receive(:parse) { {} }
|
43
|
+
expect(driver).to receive(:adb).with("pull /data/local/od-output.json #{temp_file.path}")
|
44
|
+
expect(driver).to receive(:adb).with('shell rm /data/local/od-output.json')
|
45
|
+
subject
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#run' do
|
50
|
+
context 'with a device id' do
|
51
|
+
let(:device_id) { '1234abcd' }
|
52
|
+
|
53
|
+
context 'with integer arguments' do
|
54
|
+
subject { driver.run(class_name, method_signature, *args) }
|
55
|
+
it do
|
56
|
+
allow(driver).to receive(:drive)
|
57
|
+
expect(driver).to receive(:drive).with("#{driver_stub} 'some.Klazz' 'run' I:1 I:2 I:3")
|
58
|
+
subject
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'without a device id' do
|
64
|
+
let(:device_id) { '' }
|
65
|
+
|
66
|
+
context 'with string argument' do
|
67
|
+
let(:class_name) { 'string/Klazz' }
|
68
|
+
let(:method_signature) { 'run(Ljava/lang/String;)V' }
|
69
|
+
let(:args) { 'hello string' }
|
70
|
+
|
71
|
+
subject { driver.run(class_name, method_signature, args) }
|
72
|
+
it do
|
73
|
+
allow(driver).to receive(:drive)
|
74
|
+
expect(driver).to receive(:drive).with(
|
75
|
+
"#{driver_stub} 'string.Klazz' 'run' java.lang.String:[104,101,108,108,111,32,115,116,114,105,110,103]"
|
76
|
+
)
|
77
|
+
subject
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe StringDecryptor do
|
4
|
+
let(:data_path) { 'spec/data/plugins' }
|
5
|
+
let(:driver) { instance_double('Driver') }
|
6
|
+
let(:smali_files) { [SmaliFile.new(file_path)] }
|
7
|
+
let(:method) { smali_files.first.methods.first }
|
8
|
+
let(:batch) { { id: '123' } }
|
9
|
+
let(:plugin) { StringDecryptor.new(driver, smali_files, [method]) }
|
10
|
+
|
11
|
+
describe '#process' do
|
12
|
+
subject { plugin.process }
|
13
|
+
|
14
|
+
context 'with string_decrypt.smali' do
|
15
|
+
let(:file_path) { "#{data_path}/string_decrypt.smali" }
|
16
|
+
let(:batch_item) { ["const-string v0, \"encrypted\"\n\n invoke-static {v0}, Lorg/cf/StringDecrypt;->decrypt(Ljava/lang/String;)Ljava/lang/String;\n\n move-result-object v0", 'v0'] }
|
17
|
+
|
18
|
+
it do
|
19
|
+
expect(driver).to receive(:make_target).with('org/cf/StringDecrypt', 'decrypt(Ljava/lang/String;)', 'encrypted').and_return(batch)
|
20
|
+
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc))
|
21
|
+
subject
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Undexguard do
|
4
|
+
let(:data_path) { 'spec/data/plugins' }
|
5
|
+
let(:driver) { instance_double('Driver') }
|
6
|
+
let(:smali_files) { [SmaliFile.new(file_path)] }
|
7
|
+
let(:method) { smali_files.first.methods.first }
|
8
|
+
let(:batch) { { id: '123' } }
|
9
|
+
let(:plugin) { Undexguard.new(driver, smali_files, [method]) }
|
10
|
+
|
11
|
+
describe '#process' do
|
12
|
+
subject { plugin.process }
|
13
|
+
|
14
|
+
context 'with string_lookup_3int.smali' do
|
15
|
+
let(:file_path) { "#{data_path}/string_lookup_3int.smali" }
|
16
|
+
let(:batch_item) { ["const/4 v0, 0x0\n\n const/4 v1, 0x1\n\n const/4 v2, 0x2\n\n invoke-static {v0, v1, v2}, Lorg/cf/StringLookup;->lookup(III)Ljava/lang/String;\n\n move-result-object v0", 'v0'] }
|
17
|
+
|
18
|
+
it do
|
19
|
+
expect(driver).to receive(:make_target).with('org/cf/StringLookup', 'lookup(III)', 0, 1, 2).and_return(batch)
|
20
|
+
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc))
|
21
|
+
subject
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with string_lookup_1int.smali' do
|
26
|
+
let(:file_path) { "#{data_path}/string_lookup_1int.smali" }
|
27
|
+
let(:batch_item) { ["const/4 v0, 0x0\n\n invoke-static {v0}, Lorg/cf/StringLookup;->lookup(I)Ljava/lang/String;\n\n move-result-object v0", 'v0'] }
|
28
|
+
|
29
|
+
it do
|
30
|
+
expect(driver).to receive(:make_target).with('org/cf/StringLookup', 'lookup(I)', 0).and_return(batch)
|
31
|
+
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc))
|
32
|
+
subject
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with bytes_decrypt.smali' do
|
37
|
+
let(:file_path) { "#{data_path}/bytes_decrypt.smali" }
|
38
|
+
let(:batch_item) { ["const-string v0, \"asdf\"\n\n invoke-virtual {v0}, Ljava/lang/String;->getBytes()[B\n\n move-result-object v0\n\n invoke-static {v0}, Lorg/cf/BytesDecrypt;->decrypt([B)Ljava/lang/String;\n\n move-result-object v0", 'v0'] }
|
39
|
+
|
40
|
+
it do
|
41
|
+
expect(driver).to receive(:make_target).with('org/cf/BytesDecrypt', 'decrypt([B)', [97, 115, 100, 102]).and_return(batch)
|
42
|
+
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc))
|
43
|
+
subject
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with multi_bytes_decrypt.smali' do
|
48
|
+
let(:file_path) { "#{data_path}/multi_bytes_decrypt.smali" }
|
49
|
+
let(:batch_id) { '9e31b050ec6334ed1c9ec57686b5bd765bd811410bc240141dfc466ef0719bfd' }
|
50
|
+
let(:batch) { { id: batch_id } }
|
51
|
+
let(:batch_item) { ["const-string v0, \"string1\"\n\n new-instance v1, Ljava/lang/String;\n\n invoke-static {v0}, Lorg/cf/MultiBytesDecrypt;->doThing1(Ljava/lang/String;)[B\n\n move-result-object v2\n\n const-string v3, \"string2\"\n\n invoke-static {v2, v3}, Lorg/cf/MultiBytesDecrypt;->doThing2([BLjava/lang/String;)[B\n\n move-result-object v2\n\n invoke-static {v2}, Lorg/cf/MultiBytesDecrypt;->doThing3([B)[B\n\n move-result-object v2\n\n invoke-direct {v1, v2}, Ljava/lang/String;-><init>([B)V", 'v1'] }
|
52
|
+
let(:iv_bytes) { '[1,2,3]' }
|
53
|
+
let(:enc_bytes) { '[4,5,6]' }
|
54
|
+
let(:dec_bytes) { '[65]' }
|
55
|
+
|
56
|
+
it do
|
57
|
+
expect(driver).to receive(:run).with('org/cf/MultiBytesDecrypt', 'doThing1(Ljava/lang/String;)', 'string1').and_return(iv_bytes)
|
58
|
+
expect(driver).to receive(:run).with('org/cf/MultiBytesDecrypt', 'doThing2([BLjava/lang/String;)', iv_bytes, 'string2').and_return(enc_bytes)
|
59
|
+
expect(driver).to receive(:run).with('org/cf/MultiBytesDecrypt', 'doThing3([B)', enc_bytes).and_return(dec_bytes)
|
60
|
+
expect(Plugin).to receive(:apply_outputs).with(
|
61
|
+
{ batch_id => %w(success A) },
|
62
|
+
{ method => { batch => [batch_item] } },
|
63
|
+
kind_of(Proc)
|
64
|
+
)
|
65
|
+
subject
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Unreflector do
|
4
|
+
let(:data_path) { 'spec/data/plugins' }
|
5
|
+
let(:driver) { instance_double('Driver') }
|
6
|
+
let(:smali_files) { [SmaliFile.new(file_path)] }
|
7
|
+
let(:method) { smali_files.first.methods.first }
|
8
|
+
let(:plugin) { Unreflector.new(driver, smali_files, [method]) }
|
9
|
+
|
10
|
+
describe '#process' do
|
11
|
+
subject { plugin.process }
|
12
|
+
|
13
|
+
context 'with class_forname.smali' do
|
14
|
+
let(:file_path) { "#{data_path}/class_forname.smali" }
|
15
|
+
let(:batch_id) { 'f8dc3df1acedbee81e5ff984eb026b76eb5e4bdf6d401fb12e081b8bcdb0cd55' }
|
16
|
+
let(:batch) { { id: batch_id } }
|
17
|
+
let(:batch_item) { ["const-string v0, \"android.content.Intent\"\n\n invoke-static {v0}, Ljava/lang/Class;->forName(Ljava/lang/String;)Ljava/lang/Class;\n\n move-result-object v0", 'v0'] }
|
18
|
+
|
19
|
+
it do
|
20
|
+
expect(Plugin).to receive(:apply_outputs).with(
|
21
|
+
{ batch_id => ['success', 'Landroid/content/Intent;'] },
|
22
|
+
{ method => { batch => [batch_item] } },
|
23
|
+
kind_of(Proc)
|
24
|
+
)
|
25
|
+
subject
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmaliField do
|
4
|
+
context 'with simple field' do
|
5
|
+
let(:class_name) { 'Lorg/cfg/MyClass;' }
|
6
|
+
let(:field_signature) { 'someField:Ljava/lang/Object;' }
|
7
|
+
let(:smali_field) { SmaliField.new(class_name, field_signature) }
|
8
|
+
subject { smali_field }
|
9
|
+
|
10
|
+
its(:class) { should eq class_name }
|
11
|
+
its(:name) { should eq 'someField' }
|
12
|
+
its(:type) { should eq 'Ljava/lang/Object;' }
|
13
|
+
its(:descriptor) { should eq "#{class_name}->#{field_signature}" }
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmaliFile do
|
4
|
+
let(:data_path) { 'spec/data/smali' }
|
5
|
+
|
6
|
+
context 'the hello world smali' do
|
7
|
+
let(:file_path) { "#{data_path}/helloworld.smali" }
|
8
|
+
let(:smali_file) { SmaliFile.new(file_path) }
|
9
|
+
let(:method_body) do
|
10
|
+
<<-EOF
|
11
|
+
|
12
|
+
.locals 2
|
13
|
+
|
14
|
+
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
|
15
|
+
const-string v1, "hello,world!"
|
16
|
+
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
|
17
|
+
|
18
|
+
return-void
|
19
|
+
EOF
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { smali_file }
|
23
|
+
its(:class) { should eq 'LHelloWorld;' }
|
24
|
+
its(:super) { should eq 'Ljava/lang/Object;' }
|
25
|
+
its(:interfaces) { should eq ['Lsome/Interface1;', 'Lsome/Interface2;'] }
|
26
|
+
its(:fields) { should eq [SmaliField.new('LHelloWorld;', 'someField:Z')] }
|
27
|
+
its(:methods) { should eq [SmaliMethod.new('LHelloWorld;', 'main([Ljava/lang/String;)V', method_body)] }
|
28
|
+
|
29
|
+
describe '#update' do
|
30
|
+
subject { smali_file.content }
|
31
|
+
it 'should update modified methods' do
|
32
|
+
allow(File).to receive(:open)
|
33
|
+
method = smali_file.methods.first
|
34
|
+
method.modified = true
|
35
|
+
method.body = "\nreturn-void\n"
|
36
|
+
smali_file.update
|
37
|
+
should eq ".class public LHelloWorld; # COMMENT;\n.super Ljava/lang/Object; # YEAH ;\n.implements Lsome/Interface1;\n.implements Lsome/Interface2;\n\n.field public static final someField:Z\n\n.method public static main([Ljava/lang/String;)V\nreturn-void\n.end method\n\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SmaliInput do
|
4
|
+
let(:data_path) { 'spec/data' }
|
5
|
+
let(:temp_dir) { '/fake/tmp/dir' }
|
6
|
+
let(:temp_file) { '/fake/tmp/file' }
|
7
|
+
|
8
|
+
context 'for input that must be disassembled with baksmali' do
|
9
|
+
let(:smali_input) do
|
10
|
+
allow(Dir).to receive(:mktmpdir).and_return(temp_dir)
|
11
|
+
allow(Tempfile).to receive(:new).and_return(temp_file)
|
12
|
+
allow(SmaliInput).to receive(:which).and_return('baksmali')
|
13
|
+
allow(SmaliInput).to receive(:exec)
|
14
|
+
allow(SmaliInput).to receive(:update_apk)
|
15
|
+
allow(SmaliInput).to receive(:extract_dex)
|
16
|
+
allow(FileUtils).to receive(:cp)
|
17
|
+
SmaliInput.new(file_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { smali_input }
|
21
|
+
|
22
|
+
context 'with an apk' do
|
23
|
+
let(:file_path) { "#{data_path}/helloworld.apk" }
|
24
|
+
its(:out_apk) { should eq 'helloworld_oracle.apk' }
|
25
|
+
its(:out_dex) { should eq temp_file }
|
26
|
+
its(:dir) { should eq temp_dir }
|
27
|
+
its(:temp_dir) { should be true }
|
28
|
+
its(:temp_dex) { should be true }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with a dex' do
|
32
|
+
let(:file_path) { "#{data_path}/helloworld.dex" }
|
33
|
+
its(:out_apk) { should be nil }
|
34
|
+
its(:out_dex) { should eq 'helloworld_oracle.dex' }
|
35
|
+
its(:dir) { should eq temp_dir }
|
36
|
+
its(:temp_dir) { should be true }
|
37
|
+
its(:temp_dex) { should be false }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'for input that must be disassembled without baksmali' do
|
42
|
+
let(:file_path) { "#{data_path}/helloworld.dex" }
|
43
|
+
let(:smali_input) do
|
44
|
+
allow(Dir).to receive(:mktmpdir).and_return(temp_dir)
|
45
|
+
allow(SmaliInput).to receive(:which).and_return(nil)
|
46
|
+
allow(SmaliInput).to receive(:exec)
|
47
|
+
SmaliInput.new(file_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
subject { smali_input }
|
51
|
+
it 'raises' do
|
52
|
+
expect raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'for unrecognized input type' do
|
57
|
+
let(:file_path) { "#{data_path}/helloworld.smali" }
|
58
|
+
let(:smali_input) do
|
59
|
+
allow(Dir).to receive(:mktmpdir).and_return(temp_dir)
|
60
|
+
SmaliInput.new(file_path)
|
61
|
+
end
|
62
|
+
|
63
|
+
subject { smali_input }
|
64
|
+
|
65
|
+
it 'raises' do
|
66
|
+
expect raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'for a directory' do
|
71
|
+
let(:file_path) { "#{data_path}/smali" }
|
72
|
+
let(:smali_input) do
|
73
|
+
allow(FileUtils).to receive(:rm_rf)
|
74
|
+
allow(SmaliInput).to receive(:compile)
|
75
|
+
SmaliInput.new(file_path)
|
76
|
+
end
|
77
|
+
|
78
|
+
subject { smali_input }
|
79
|
+
|
80
|
+
its(:out_apk) { should be nil }
|
81
|
+
its(:out_dex) { should be nil }
|
82
|
+
its(:dir) { should eq file_path }
|
83
|
+
its(:temp_dir) { should be false }
|
84
|
+
its(:temp_dex) { should be true }
|
85
|
+
it do
|
86
|
+
expect(SmaliInput).to receive(:compile)
|
87
|
+
subject
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|