Permalink
Browse files

Add indexed string + class lookups

Reference sample: d3becbee846560d0ffa4f3cda708d69a98dff92785b7412d763f810c51c0b091
  • Loading branch information...
CalebFenton committed Oct 28, 2017
1 parent 6bb6f0c commit cf44cd7aa5e81d5b0bc9588150b81a0fcdc575fe
@@ -0,0 +1,67 @@
require_relative '../logging'
require_relative '../utility'
class IndexedClassLookup < Plugin
attr_reader :optimizations
include Logging
include CommonRegex
CLASS_DECRYPT = Regexp.new(
'^[ \t]*(' +
(CONST_NUMBER_CAPTURE + '\s+') +
'(?:\:[^\n]+\n\s*)?' + # May have a label between const and invoke
'invoke-static \{\2\}, L([^;]+);->([^\(]+\(I\))Ljava/lang/Class;' \
'\s+' +
MOVE_RESULT_OBJECT + ')'
)
MODIFIER = -> (original, output, out_reg) do
# Put the labels back if any were removed
labels = original.split("\n").select { |l| l.lstrip.start_with?(':') }
labels << "\n " unless labels.empty?
"#{labels.join("\n")}const-class #{out_reg}, #{output.split('').collect { |e| e.inspect[1..-2] }.join}"
end
# Sometimes class name lookup doesn't work and null is returned
FILTER = -> (_, output, out_reg) { output == 'null' }
def initialize(driver, smali_files, methods)
@driver = driver
@smali_files = smali_files
@methods = methods
@optimizations = Hash.new(0)
end
def process
method_to_target_to_contexts = {}
@methods.each do |method|
logger.info("Decrypting indexed classes #{method.descriptor}")
target_to_contexts = {}
target_to_contexts.merge!(decrypt_classes(method))
target_to_contexts.map { |_, v| v.uniq! }
method_to_target_to_contexts[method] = target_to_contexts unless target_to_contexts.empty?
end
made_changes = false
made_changes |= Plugin.apply_batch(@driver, method_to_target_to_contexts, MODIFIER, FILTER)
made_changes
end
private
def decrypt_classes(method)
target_to_contexts = {}
matches = method.body.scan(CLASS_DECRYPT)
@optimizations[:class_lookups] += matches.size if matches
matches.each do |original, _, index, class_name, method_signature, out_reg|
target = @driver.make_target(
class_name, method_signature, index.to_i(16)
)
target_to_contexts[target] = [] unless target_to_contexts.key?(target)
target_to_contexts[target] << [original, out_reg]
end
target_to_contexts
end
end
@@ -0,0 +1,59 @@
require_relative '../logging'
require_relative '../utility'
class IndexedStringLookup < Plugin
attr_reader :optimizations
include Logging
include CommonRegex
STRING_DECRYPT = Regexp.new(
'^[ \t]*(' +
(CONST_NUMBER_CAPTURE + '\s+') +
'invoke-static \{\2\}, L([^;]+);->([^\(]+\(I\))Ljava/lang/String;' \
'\s+' +
MOVE_RESULT_OBJECT + ')'
)
MODIFIER = -> (_, output, out_reg) { "const-string #{out_reg}, \"#{output.split('').collect { |e| e.inspect[1..-2] }.join}\"" }
def initialize(driver, smali_files, methods)
@driver = driver
@smali_files = smali_files
@methods = methods
@optimizations = Hash.new(0)
end
def process
method_to_target_to_contexts = {}
@methods.each do |method|
logger.info("Decrypting indexed strings #{method.descriptor}")
target_to_contexts = {}
target_to_contexts.merge!(decrypt_strings(method))
target_to_contexts.map { |_, v| v.uniq! }
method_to_target_to_contexts[method] = target_to_contexts unless target_to_contexts.empty?
end
made_changes = false
made_changes |= Plugin.apply_batch(@driver, method_to_target_to_contexts, MODIFIER)
made_changes
end
private
def decrypt_strings(method)
target_to_contexts = {}
matches = method.body.scan(STRING_DECRYPT)
@optimizations[:string_lookups] += matches.size if matches
matches.each do |original, index, class_name, method_signature, out_reg|
target = @driver.make_target(
class_name, method_signature, index.to_i(16)
)
target_to_contexts[target] = [] unless target_to_contexts.key?(target)
target_to_contexts[target] << [original, out_reg]
end
target_to_contexts
end
end
@@ -0,0 +1,15 @@
.class public Lorg/cf/ClassLookup;
.super Ljava/lang/Object;
.method public static doStuff()V
.locals 1
const v0, 0x19189b0e
:some_label
invoke-static {v0}, Lxjmurla/gqscntaej/bfdiays/g;->c(I)Ljava/lang/Class;
move-result-object v0
return-void
.end method
@@ -0,0 +1,14 @@
.class public Lorg/cf/StringLookup;
.super Ljava/lang/Object;
.method public static doStuff()V
.locals 1
const v0, 0x320fb210
invoke-static {v0}, Lxjmurla/gqscntaej/bfdiays/f;->a(I)Ljava/lang/String;
move-result-object v0
return-void
.end method
@@ -0,0 +1,25 @@
require 'spec_helper'
describe IndexedClassLookup do
let(:data_path) { 'spec/data/plugins' }
let(:driver) { instance_double('Driver') }
let(:smali_files) { [SmaliFile.new(file_path)] }
let(:method) { smali_files.first.methods.first }
let(:batch) { { id: '123' } }
let(:plugin) { IndexedClassLookup.new(driver, smali_files, [method]) }
describe '#process' do
subject { plugin.process }
context 'with class_lookup.smali' do
let(:file_path) { "#{data_path}/class_lookup.smali" }
let(:batch_item) { ["const v0, 0x19189b0e\n\n :some_label\n invoke-static {v0}, Lxjmurla/gqscntaej/bfdiays/g;->c(I)Ljava/lang/Class;\n\n move-result-object v0", 'v0'] }
it do
expect(driver).to receive(:make_target).with('xjmurla/gqscntaej/bfdiays/g', 'c(I)', 421042958).and_return(batch)
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc), kind_of(Proc))
subject
end
end
end
end
@@ -0,0 +1,25 @@
require 'spec_helper'
describe IndexedStringLookup do
let(:data_path) { 'spec/data/plugins' }
let(:driver) { instance_double('Driver') }
let(:smali_files) { [SmaliFile.new(file_path)] }
let(:method) { smali_files.first.methods.first }
let(:batch) { { id: '123' } }
let(:plugin) { IndexedStringLookup.new(driver, smali_files, [method]) }
describe '#process' do
subject { plugin.process }
context 'with string_lookup.smali' do
let(:file_path) { "#{data_path}/string_lookup.smali" }
let(:batch_item) { ["const v0, 0x320fb210\n\n invoke-static {v0}, Lxjmurla/gqscntaej/bfdiays/f;->a(I)Ljava/lang/String;\n\n move-result-object v0", 'a(I)'] }
it do
expect(driver).to receive(:make_target).with('0x320fb210', 'xjmurla/gqscntaej/bfdiays/f', 0).and_return(batch)
expect(Plugin).to receive(:apply_batch).with(driver, { method => { batch => [batch_item] } }, kind_of(Proc))
subject
end
end
end
end

0 comments on commit cf44cd7

Please sign in to comment.