Update randomizer for progress

GSoC/Meterpreter_Web_Console
Wei Chen 2018-06-22 18:22:29 -05:00
parent 8f5ad7c1cb
commit 90bc7d2294
8 changed files with 165 additions and 14 deletions

View File

@ -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

View File

@ -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}"

View File

@ -10,7 +10,7 @@ module Metasploit
class OutputDebugString < Base
def initialize
super
@dep = 'Windows.h'
@dep = ['OutputDebugString']
end
def stub

View File

@ -10,7 +10,7 @@ module Metasploit
class Printf < Base
def initialize
super
@dep = ''
@dep = ['printf']
end
def stub

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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