Update randomizer for progress
parent
8f5ad7c1cb
commit
90bc7d2294
|
@ -11,14 +11,41 @@ module Metasploit
|
|||
attr_reader :code
|
||||
|
||||
def initialize
|
||||
@dep = ''
|
||||
@dep = []
|
||||
@code = normalized_stub
|
||||
end
|
||||
|
||||
# Override this method when you inherit this class.
|
||||
# The method should return the source of the stub you're strying to create,
|
||||
# as a C function.
|
||||
# For example:
|
||||
# %Q|
|
||||
# void printf(const char*);
|
||||
# void stub() {
|
||||
# printf("hello world\n");
|
||||
# }|
|
||||
# Notice if you are using a function like the above, you must declare/define that
|
||||
# beforehand. The function declaration will not be used in the final source code.
|
||||
def stub
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
# Checks whether this class is suitable for the code.
|
||||
#
|
||||
# @param parser [Metasm::C::Parser]
|
||||
# @return [Boolean]
|
||||
def good_dep?(parser)
|
||||
# The difference between @dep and parser.toplevel.symbol.keys
|
||||
# is the list of functions not being supported by the original code.
|
||||
ready_function_names = parser.toplevel.symbol.keys
|
||||
delta = dep - ready_function_names
|
||||
if delta.empty?
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def normalized_stub
|
||||
stub_parser = Metasploit::Framework::Obfuscation::CRandomizer::Utility.parse(stub)
|
||||
stub_parser.toplevel.statements.last.var.initializer.statements
|
||||
|
|
|
@ -10,6 +10,10 @@ module Metasploit
|
|||
attr_accessor :functions
|
||||
attr_reader :max_functions
|
||||
|
||||
# Initializes a Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection instance.
|
||||
#
|
||||
# @param max_functions [Integer] Max number of fake functions to generate.
|
||||
# @return [Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection]
|
||||
def initialize(max_functions)
|
||||
@functions = []
|
||||
@max_functions = max_functions
|
||||
|
@ -17,20 +21,29 @@ module Metasploit
|
|||
self
|
||||
end
|
||||
|
||||
# Yields a list of fake functions available.
|
||||
def each
|
||||
functions.each do |f|
|
||||
yield f
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a fake function from the FakeFunctionCollection object.
|
||||
#
|
||||
# @return [Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunction]
|
||||
def sample
|
||||
functions.sample
|
||||
end
|
||||
|
||||
# Returns a string that joins the fake functions
|
||||
def to_s
|
||||
functions.join("\n")
|
||||
end
|
||||
|
||||
# Asks the FakeFunctionCollection if a function is available.
|
||||
#
|
||||
# @param name [String]
|
||||
# @return [Boolean]
|
||||
def has_function_name?(name)
|
||||
functions.each do |f|
|
||||
if f.var.name == name
|
||||
|
@ -41,12 +54,14 @@ module Metasploit
|
|||
false
|
||||
end
|
||||
|
||||
# Checks if the collection is empty or not.
|
||||
def empty?
|
||||
functions.empty?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Generates a list of fake functions to use.
|
||||
def populate
|
||||
max_functions.times do |i|
|
||||
func_name = "function#{i}"
|
||||
|
|
|
@ -10,7 +10,7 @@ module Metasploit
|
|||
class OutputDebugString < Base
|
||||
def initialize
|
||||
super
|
||||
@dep = 'Windows.h'
|
||||
@dep = ['OutputDebugString']
|
||||
end
|
||||
|
||||
def stub
|
||||
|
|
|
@ -10,7 +10,7 @@ module Metasploit
|
|||
class Printf < Base
|
||||
def initialize
|
||||
super
|
||||
@dep = ''
|
||||
@dep = ['printf']
|
||||
end
|
||||
|
||||
def stub
|
||||
|
|
|
@ -6,14 +6,25 @@ module Metasploit
|
|||
module CRandomizer
|
||||
|
||||
class Modifier
|
||||
attr_reader :parser
|
||||
attr_reader :fake_functions
|
||||
attr_reader :weight
|
||||
|
||||
def initialize(f, w)
|
||||
# Initializes a Metasploit::Framework::Obfuscation::CRandomizer::Modifier instance.
|
||||
#
|
||||
# @param p [Metasploit::C::Parser]
|
||||
# @param f [Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection]
|
||||
# @param w [Integer] Weight of the randomness.
|
||||
def initialize(p, f, w)
|
||||
@parser = p
|
||||
@fake_functions = f
|
||||
@weight = w
|
||||
end
|
||||
|
||||
# Modifies different if-else blocks recursively.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
# @return [Metasm::C::Declaration]
|
||||
def modify_if_else_blocks(s)
|
||||
modify_if(s)
|
||||
modify_else_if(s)
|
||||
|
@ -21,6 +32,10 @@ module Metasploit
|
|||
s
|
||||
end
|
||||
|
||||
# Modifies an if block.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
# return [void]
|
||||
def modify_if(s)
|
||||
new_if_statements = []
|
||||
|
||||
|
@ -33,6 +48,10 @@ module Metasploit
|
|||
s.bthen.statements = new_if_statements
|
||||
end
|
||||
|
||||
# Modifies an else-if block.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
# @param [void]
|
||||
def modify_else_if(s)
|
||||
# There could be multiple else if blocks,
|
||||
# this gives the current else if block
|
||||
|
@ -54,6 +73,9 @@ module Metasploit
|
|||
end
|
||||
end
|
||||
|
||||
# Modifies an else block.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
def modify_else(s)
|
||||
else_block = s.belse
|
||||
|
||||
|
@ -75,6 +97,9 @@ module Metasploit
|
|||
else_block.statements = new_else_statements
|
||||
end
|
||||
|
||||
# Modifies a for block.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
def modify_for(s)
|
||||
new_for_statements = []
|
||||
|
||||
|
@ -89,6 +114,9 @@ module Metasploit
|
|||
s
|
||||
end
|
||||
|
||||
# Modifies a nested block.
|
||||
#
|
||||
# @param s [Metasm::C::Declaration]
|
||||
def modify_nested_blocks(s)
|
||||
case s
|
||||
when Metasm::C::If
|
||||
|
@ -98,6 +126,9 @@ module Metasploit
|
|||
end
|
||||
end
|
||||
|
||||
# Modifies a function.
|
||||
#
|
||||
# @param s [Metasploit::C::Declaration]
|
||||
def modify_function(s)
|
||||
function_statements = s.var.initializer.statements
|
||||
new_function_statements = []
|
||||
|
@ -126,11 +157,18 @@ module Metasploit
|
|||
|
||||
private
|
||||
|
||||
# Returns fake statements.
|
||||
#
|
||||
# @param s [Metasploit::C::Declaration]
|
||||
# @return [Array<Metasm::C::CExpression>]
|
||||
def get_fake_statement(s=nil)
|
||||
random_statements = Metasploit::Framework::Obfuscation::CRandomizer::RandomStatements.new(fake_functions, s)
|
||||
random_statements = Metasploit::Framework::Obfuscation::CRandomizer::RandomStatements.new(parser, fake_functions, s)
|
||||
random_statements.get
|
||||
end
|
||||
|
||||
# Returns a boolean indicating whether a random is above (or equal to) a number or not.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def feeling_lucky?
|
||||
n = (rand * 100).to_i
|
||||
weight >= n
|
||||
|
|
|
@ -10,15 +10,22 @@ module Metasploit
|
|||
attr_accessor :max_random_weight
|
||||
attr_accessor :fake_functions_collection
|
||||
|
||||
# Initializes a Metasploit::Framework::Obfuscation::CRandomizer::Parser instance.
|
||||
#
|
||||
# @param weight [Integer] Randomness of the code.
|
||||
# @param fake_functions [Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection]
|
||||
def initialize(weight, fake_functions)
|
||||
@max_random_weight = weight
|
||||
@fake_functions_collection = fake_functions
|
||||
end
|
||||
|
||||
# Returns a parser.
|
||||
#
|
||||
# @param template [String] Soure code to parse.
|
||||
# @return [Metasm::C::Parser]
|
||||
def parse(template)
|
||||
modifier = Metasploit::Framework::Obfuscation::CRandomizer::Modifier.new(fake_functions_collection, max_random_weight)
|
||||
|
||||
main_parser = Metasploit::Framework::Obfuscation::CRandomizer::Utility.parse(template)
|
||||
modifier = Metasploit::Framework::Obfuscation::CRandomizer::Modifier.new(main_parser, fake_functions_collection, max_random_weight)
|
||||
main_parser.toplevel.statements.each do |s|
|
||||
case s.var.type
|
||||
when Metasm::C::Function
|
||||
|
|
|
@ -7,23 +7,40 @@ module Metasploit
|
|||
|
||||
class RandomStatements
|
||||
|
||||
attr_reader :fake_functions
|
||||
attr_reader :parser
|
||||
attr_reader :fake_function_collection
|
||||
attr_reader :function_list
|
||||
|
||||
def initialize(f, s=nil)
|
||||
@fake_functions = f
|
||||
# Initializes the RandomStatements class.
|
||||
#
|
||||
# @param fake_functions [Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection]
|
||||
# @param s [Metasm::C::Declaration]
|
||||
def initialize(p, fake_functions, s=nil)
|
||||
@parser = p
|
||||
@fake_function_collection = fake_functions
|
||||
@function_list = [ Proc.new { get_random_statements } ]
|
||||
if s && !f.has_function_name?(s.var.name)
|
||||
|
||||
# Only generate fake function calls when the function we are modifying isn't
|
||||
# from one of those fake functions (to avoid a recursion).
|
||||
if s && !fake_function_collection.has_function_name?(s.var.name)
|
||||
@function_list << Proc.new { get_random_function_call }
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a random statement.
|
||||
#
|
||||
# @return [Array<Metasm::C::CExpression>]
|
||||
# @return [Array<Metasm::C::Declaration>]
|
||||
def get
|
||||
function_list.sample.call
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns function arguments as a string.
|
||||
#
|
||||
# @param args [Array<Metasm::C::Variable>]
|
||||
# @return [String]
|
||||
def make_func_arg_str(args)
|
||||
arg_array = []
|
||||
|
||||
|
@ -41,6 +58,10 @@ module Metasploit
|
|||
%Q|(#{arg_array.join(', ')})|
|
||||
end
|
||||
|
||||
# Returns the arguments (in string) for function declaration.
|
||||
#
|
||||
# @param args [Array<Metasm::C::Variable]
|
||||
# @return [String]
|
||||
def make_func_declare_arg_str(args)
|
||||
arg_array = []
|
||||
args.each do |a|
|
||||
|
@ -57,22 +78,36 @@ module Metasploit
|
|||
%Q|(#{arg_array.join(', ')})|
|
||||
end
|
||||
|
||||
# Returns a random statement from the Code Factory, excluding:
|
||||
# * The base class
|
||||
# * FakeFunction class
|
||||
# * FakeFunctionCollection class
|
||||
#
|
||||
# @return [Array]
|
||||
def get_random_statements
|
||||
ignored_classes = [:Base, :FakeFunction, :FakeFunctionCollection]
|
||||
class_name = Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory.constants.select { |c|
|
||||
next if ignored_classes.include?(c)
|
||||
Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory.const_get(c).instance_of?(Class)
|
||||
}.sample
|
||||
Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory.const_get(class_name).new.code
|
||||
|
||||
instance = Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory.const_get(class_name).new
|
||||
|
||||
if instance.good_dep?(parser)
|
||||
return Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory.const_get(class_name).new.code
|
||||
else
|
||||
# Call again
|
||||
get_random_statements
|
||||
end
|
||||
end
|
||||
|
||||
# This function is kind of dangerous, because it could cause an
|
||||
# infinitely loop by accident when random functions call each other.
|
||||
def get_random_function_call
|
||||
# There is no fake function collection
|
||||
return [] if fake_functions.empty?
|
||||
return [] if fake_function_collection.empty?
|
||||
|
||||
fake_function = fake_functions.sample
|
||||
fake_function = fake_function_collection.sample
|
||||
fake_function_name = fake_function.var.name
|
||||
fake_function_args = fake_function.var.type.args
|
||||
fake_function_declare_args_str = make_func_declare_arg_str(fake_function_args)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
msfbase = __FILE__
|
||||
while File.symlink?(msfbase)
|
||||
msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
|
||||
end
|
||||
$:.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', '..', 'lib')))
|
||||
|
||||
require 'metasploit/framework/obfuscation/crandomizer'
|
||||
|
||||
fake_function_size = rand(0..3)
|
||||
fake_function_collection = Metasploit::Framework::Obfuscation::CRandomizer::CodeFactory::FakeFunctionCollection.new(fake_function_size)
|
||||
|
||||
template = %Q|
|
||||
#define MSG "BLAH"
|
||||
|
||||
void printf(const char*);
|
||||
|
||||
#{fake_function_collection}
|
||||
|
||||
void test() {
|
||||
printf(MSG);
|
||||
}
|
||||
|
||||
int main() {
|
||||
return 0;
|
||||
}|
|
||||
|
||||
p = Metasploit::Framework::Obfuscation::CRandomizer::Parser.new(90, fake_function_collection)
|
||||
result = p.parse(template)
|
||||
puts result
|
Loading…
Reference in New Issue