Exemplo n.º 1
0
    def test_get_tokenstream(self):
        yara_file = yaramod.Yaramod().parse_string('''
rule empty_rule {
    meta:
        key = "value"
    condition:
        true
}''')

        self.assertEqual(len(yara_file.rules), 1)

        rule = yara_file.rules[0]
        rule.metas[0].value = yaramod.Literal('another value')

        ts = yara_file.tokenstream
        self.assertFalse(ts.empty)
        self.assertEqual(ts.front.pure_text, '\n')
        self.assertEqual(ts.back.pure_text, '}')
        self.assertEqual(ts.tokens_as_text, [ '\n',
            'rule', 'empty_rule', '{', '\n',
            'meta', ':', '\n',
            'key', '=', 'another value', '\n',
            'condition', ':', '\n', 'true', '\n',
            '}'
        ])
        condition_ts = rule.condition.tokenstream
        self.assertEqual(condition_ts.tokens_as_text, [ '\n',
            'rule', 'empty_rule', '{', '\n',
            'meta', ':', '\n',
            'key', '=', 'another value', '\n',
            'condition', ':', '\n', 'true', '\n',
            '}'
        ])
Exemplo n.º 2
0
    def test_custom_module_interface(self):
        modules = yaramod.Yaramod(yaramod.Features.AllCurrent, "./tests/python/testing_modules").modules

        # module module_test
        self.assertTrue("module_test" in modules)
        module_symbol = modules["module_test"].structure
        self.assertEqual("module_test", module_symbol.name)
        self.assertTrue(module_symbol.is_structure)
        cuckoo_attributes = module_symbol.attributes

        self.assertTrue("structure_test" in cuckoo_attributes)
        structure_symbol = cuckoo_attributes["structure_test"]
        self.assertTrue(structure_symbol.is_structure)
        structure_attributes = structure_symbol.attributes

        self.assertTrue("function_test" in structure_attributes)
        function_symbol = structure_attributes["function_test"]
        self.assertTrue(function_symbol.is_function)
        self.assertEqual(function_symbol.return_type, yaramod.ExpressionType.String)
        function_overloads = function_symbol.overloads
        self.assertEqual(len(function_overloads), 2)
        self.assertEqual(function_overloads[0], [yaramod.ExpressionType.Regexp])
        self.assertEqual(function_overloads[1], [yaramod.ExpressionType.Regexp, yaramod.ExpressionType.String])
        function_documentations = function_symbol.documentations
        print(function_documentations)
        self.assertEqual(len(function_documentations), 2)
        self.assertEqual(function_documentations[0], "Testing function overload documentation.")
        self.assertEqual(function_documentations[1], "Testing function cool overload documentation.")

        self.assertTrue("value_test" in cuckoo_attributes)
        value_symbol = cuckoo_attributes["value_test"]
        self.assertTrue(value_symbol.is_value)
        self.assertEqual(value_symbol.documentation, "Testing value documentation. Example: ```module_test.value_test > 10```")
Exemplo n.º 3
0
    def test_modifying_visitor_eq_expression(self):
        class EqModifyer(yaramod.ModifyingVisitor):
            def add(self, yara_file: yaramod.YaraFile):
                for rule in yara_file.rules:
                    rule.condition = self.modify(rule.condition)

            def visit_EqExpression(self, expr: yaramod.Expression):
                context = yaramod.TokenStreamContext(expr)
                expr.left_operand.accept(self)
                expr.right_operand.accept(self)
                output = (yaramod.YaraExpressionBuilder(expr.right_operand) !=
                          yaramod.YaraExpressionBuilder(
                              expr.left_operand)).get()

                self.cleanUpTokenStreams(context, output)
                return output

        yara_file = yaramod.Yaramod().parse_string(r'''
rule rule_with_regexp_in_fnc_call {
	strings:
		$str1 = "a"
		$str2222 = "b"
	condition:
		!str1 == !str2222
}''')

        regexp_icase_adder = EqModifyer()
        regexp_icase_adder.add(yara_file)

        self.assertEqual(len(yara_file.rules), 1)
        rule = yara_file.rules[0]
        cond = rule.condition
        self.assertTrue(isinstance(cond, yaramod.NeqExpression))
        self.assertTrue(
            isinstance(cond.left_operand, yaramod.StringLengthExpression))
        self.assertTrue(
            isinstance(cond.right_operand, yaramod.StringLengthExpression))

        self.assertEqual(
            r'''rule rule_with_regexp_in_fnc_call {
	strings:
		$str1 = "a"
		$str2222 = "b"
	condition:
		!str2222 != !str1
}''', yara_file.text)
        expected = r'''
rule rule_with_regexp_in_fnc_call
{
	strings:
		$str1 = "a"
		$str2222 = "b"
	condition:
		!str2222 != !str1
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 4
0
    def test_simple_modifying_visitor(self):
        class StringExpressionUpper(yaramod.ModifyingVisitor):
            def add(self, yara_file: yaramod.YaraFile):
                for rule in yara_file.rules:
                    self.modify(rule.condition)

            def visit_StringExpression(self, expr: yaramod.Expression):
                expr.id = expr.id.upper()

        yara_file = yaramod.Yaramod().parse_string(r'''
import "cuckoo"
rule rule_with_regexp_in_fnc_call {
	strings:
		$str1 = "s"
		$str2 = "s"
	condition:
		$str1 and $str2
}''')

        visitor = StringExpressionUpper()
        visitor.add(yara_file)

        self.assertEqual(len(yara_file.rules), 1)
        rule = yara_file.rules[0]
        cond = rule.condition
        self.assertTrue(isinstance(cond, yaramod.AndExpression))
        self.assertTrue(
            isinstance(cond.right_operand, yaramod.StringExpression))
        self.assertEqual(cond.left_operand.id, "$STR1")
        self.assertTrue(isinstance(cond.left_operand,
                                   yaramod.StringExpression))
        self.assertEqual(cond.right_operand.id, "$STR2")

        self.assertEqual(
            r'''import "cuckoo"

rule rule_with_regexp_in_fnc_call {
	strings:
		$STR1 = "s"
		$STR2 = "s"
	condition:
		$STR1 and $STR2
}''', yara_file.text)
        expected = r'''
import "cuckoo"

rule rule_with_regexp_in_fnc_call
{
	strings:
		$STR1 = "s"
		$STR2 = "s"
	condition:
		$STR1 and
		$STR2
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 5
0
def main():
    if len(sys.argv) != 2:
        sys.exit('Usage: {} YARA_FILE'.format(sys.argv[0]))

    dumper = Dumper()

    ymod_parser = yaramod.Yaramod()
    yara_file = ymod_parser.parse_file(sys.argv[1])
    for rule in yara_file.rules:
        print('==== RULE: {}'.format(rule.name))
        dumper.observe(rule.condition)
Exemplo n.º 6
0
    def test_module_interface(self):
        modules = yaramod.Yaramod().modules

        # module cuckoo
        self.assertTrue("cuckoo" in modules)
        cuckoo_symbol = modules["cuckoo"].structure
        self.assertEqual("cuckoo", cuckoo_symbol.name)
        self.assertTrue(cuckoo_symbol.is_structure)
        cuckoo_attributes = cuckoo_symbol.attributes

        self.assertTrue("network" in cuckoo_attributes)
        network_symbol = cuckoo_attributes["network"]
        self.assertTrue(network_symbol.is_structure)
        network_attributes = network_symbol.attributes

        self.assertTrue("http_get" in network_attributes)
        http_get_symbol = network_attributes["http_get"]
        self.assertTrue(http_get_symbol.is_function)
        self.assertEqual("http_get", http_get_symbol.name)
        self.assertEqual(http_get_symbol.return_type, yaramod.ExpressionType.Int)
        http_get_overloads = http_get_symbol.overloads
        self.assertEqual(len(http_get_overloads), 1)
        self.assertEqual(http_get_overloads[0], [yaramod.ExpressionType.Regexp])

        # module pe
        self.assertTrue("pe" in modules)
        pe_symbol = modules["pe"].structure
        self.assertEqual("pe", pe_symbol.name)
        self.assertTrue(pe_symbol.is_structure)
        pe_attributes = pe_symbol.attributes

        self.assertTrue("MACHINE_UNKNOWN" in pe_attributes)
        machine_symbol = pe_attributes["MACHINE_UNKNOWN"]
        self.assertTrue(machine_symbol.is_value)
        self.assertEqual(machine_symbol.data_type, yaramod.ExpressionType.Int)

        self.assertTrue("version_info" in pe_attributes)
        version_info_symbol = pe_attributes["version_info"]
        self.assertEqual(version_info_symbol.documentation[0:10], "Dictionary")

        self.assertTrue("sections" in pe_attributes)
        section_array_symbol = pe_attributes['sections']
        self.assertEqual(section_array_symbol.name, 'sections')
        self.assertTrue(section_array_symbol.is_array)
        self.assertEqual(section_array_symbol.element_type, yaramod.ExpressionType.Object)
        self.assertEqual(section_array_symbol.documentation[0:10], 'Individual')
        section_symbol = section_array_symbol.structure
        self.assertEqual(section_symbol.name, 'sections')
        self.assertTrue(section_symbol.is_structure)
        section_attributes = section_symbol.attributes

        self.assertTrue("characteristics" in section_attributes)
Exemplo n.º 7
0
 def test_get_modulepool(self):
     ymod = yaramod.Yaramod()
     modules = ymod.modules
     self.assertTrue("cuckoo" in modules)
     self.assertTrue("dex" in modules)
     self.assertTrue("dotnet" in modules)
     self.assertTrue("elf" in modules)
     self.assertTrue("hash" in modules)
     self.assertTrue("macho" in modules)
     self.assertTrue("magic" in modules)
     self.assertTrue("math" in modules)
     self.assertTrue("pe" in modules)
     self.assertTrue("time" in modules)
Exemplo n.º 8
0
    def test_modifying_visitor_inpact_on_regexp_expression(self):
        class RegexpCaseInsesitiveAdder(yaramod.ModifyingVisitor):
            def add(self, yara_file: yaramod.YaraFile):
                for rule in yara_file.rules:
                    self.modify(rule.condition)

            def visit_RegexpExpression(self, expr: yaramod.Expression):
                output = yaramod.regexp('abc', 'i').get()
                expr.exchange_tokens(output)
                return output

        yara_file = yaramod.Yaramod().parse_string(r'''
import "cuckoo"
rule rule_with_regexp_in_fnc_call {
	condition:
		cuckoo.network.http_request(/http:\/\/someone\.doingevil\.com/)
}''')

        regexp_icase_adder = RegexpCaseInsesitiveAdder()
        regexp_icase_adder.add(yara_file)

        self.assertEqual(len(yara_file.rules), 1)
        rule = yara_file.rules[0]
        cond = rule.condition
        self.assertTrue(isinstance(cond, yaramod.FunctionCallExpression))
        self.assertEqual(len(cond.arguments), 1)
        self.assertTrue(isinstance(cond.arguments[0],
                                   yaramod.RegexpExpression))
        self.assertTrue(
            isinstance(cond.arguments[0].regexp_string, yaramod.Regexp))
        self.assertEqual(cond.arguments[0].regexp_string.text, r'/abc/i')
        self.assertEqual(cond.arguments[0].regexp_string.pure_text, rb'abc')

        self.assertEqual(
            r'''import "cuckoo"

rule rule_with_regexp_in_fnc_call {
	condition:
		cuckoo.network.http_request(/abc/i)
}''', yara_file.text)
        expected = r'''
import "cuckoo"

rule rule_with_regexp_in_fnc_call
{
	condition:
		cuckoo.network.http_request(/abc/i)
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 9
0
    def test_get_tokenstream_after_syntax_error_1(self):
        input_text = '''
rule dummy_rule {
	condition
		true
}'''
        ymod = yaramod.Yaramod()
        try:
            ymod.parse_string(input_text)
        except:
            ts = ymod.yara_file.tokenstream
            self.assertFalse(ts.empty)
            self.assertEqual(ts.front.pure_text, '\n')
            self.assertEqual(ts.back.pure_text, 'true')
Exemplo n.º 10
0
def main():
    if len(sys.argv) != 2:
        sys.exit('Usage: {} YARA_FILE'.format(sys.argv[0]))

    simplifier = BoolSimplifier()

    ymod_parser = yaramod.Yaramod()
    yara_file = ymod_parser.parse_file(sys.argv[1])
    for rule in yara_file.rules:
        print('==== RULE: {}'.format(rule.name))
        print('==== BEFORE')
        print(rule.text)
        rule.condition = simplifier.modify(rule.condition, when_deleted=yaramod.bool_val(False).get())
        print('==== AFTER')
        print(rule.text)
Exemplo n.º 11
0
    def test_get_tokenstream_after_unknown_identifier_error(self):
        input_text = '''
rule dummy_rule {
	condition:
		blah or true
}'''
        ymod = yaramod.Yaramod()
        try:
            ymod.parse_string(input_text)
        except:
            ts = ymod.yara_file.tokenstream
            self.assertFalse(ts.empty)
            self.assertEqual(ts.front.pure_text, '\n')
            # After 'blah', also 'or' got into TS, because 'blah' is not tested by the grammar, it is semantics issue
            self.assertEqual(ts.back.pure_text, 'or')
Exemplo n.º 12
0
    def test_get_tokenstream_after_unknown_module_error(self):
        input_text = '''
import "unknown"

rule dummy_rule {
	condition:
		true
}'''
        ymod = yaramod.Yaramod()
        try:
            ymod.parse_string(input_text)
        except:
            ts = ymod.yara_file.tokenstream
            self.assertFalse(ts.empty)
            # After 'unknown', also 'rule' got into TS, because 'unknown' is not tested by the grammar, it is semantics issue
            self.assertEqual(ts.tokens_as_text,
                             ['\n', 'import', 'unknown', '\n', '\n', 'rule'])
Exemplo n.º 13
0
    def test_meta_values_interface(self):
        input_text = """rule test {
    meta:
        author = "Name Surname"
        description = "Test checking the meta value tokens"
    condition:
        false
}
"""
        ymod = yaramod.Yaramod()
        yfile = ymod.parse_string(input_text)
        self.assertEqual(len(yfile.rules[0].metas), 2)

        meta = yfile.rules[0].metas[0]  # author
        self.assertTrue(hasattr(meta, "token_key"))
        token = meta.token_key
        self.assertEqual(token.location.begin.line, 3)
        self.assertEqual(token.location.begin.column, 9)
        self.assertEqual(token.location.end.line, 3)
        self.assertEqual(token.location.end.column, 14)

        self.assertTrue(hasattr(meta, "token_value"))
        token = meta.token_value
        self.assertEqual(token.location.begin.line, 3)
        self.assertEqual(token.location.begin.column, 18)
        self.assertEqual(token.location.end.line, 3)
        self.assertEqual(token.location.end.column, 31)

        meta = yfile.rules[0].metas[1]  # description
        self.assertTrue(hasattr(meta, "token_key"))
        token = meta.token_key
        self.assertEqual(token.location.begin.line, 4)
        self.assertEqual(token.location.begin.column, 9)
        self.assertEqual(token.location.end.line, 4)
        self.assertEqual(token.location.end.column, 19)

        self.assertTrue(hasattr(meta, "token_value"))
        token = meta.token_value
        self.assertEqual(token.location.begin.line, 4)
        self.assertEqual(token.location.begin.column, 23)
        self.assertEqual(token.location.end.line, 4)
        self.assertEqual(token.location.end.column, 59)
Exemplo n.º 14
0
    def test_change_meta_of_rule(self):
        yara_file = yaramod.Yaramod().parse_string('''
rule empty_rule {
	meta:
		key = "value"
	condition:
		true
}''')

        self.assertEqual(len(yara_file.rules), 1)

        rule = yara_file.rules[0]
        rule.metas[0].value = yaramod.Literal('another value')

        expected = '''
rule empty_rule
{
	meta:
		key = "another value"
	condition:
		true
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 15
0
    def test_rule_inserter(self):
        class RuleInserter(yaramod.ModifyingVisitor):
            def insert_rule(self, yara_file):
                rule_cond = yaramod.conjunction(
                    [yaramod.id('first_file'),
                     yaramod.id('second_file')])

                another_rule = yaramod.YaraRuleBuilder() \
                    .with_modifier(yaramod.RuleModifier.Private) \
                    .with_name('ANOTHER_RULE') \
                    .with_condition(rule_cond.get()) \
                    .get()

                for rule in yara_file.rules:
                    if not rule.is_private:
                        context = yaramod.TokenStreamContext(rule.condition)
                        output = yaramod.conjunction([
                            yaramod.id(another_rule.name),
                            yaramod.paren(yaramod.YaraExpressionBuilder(
                                rule.condition),
                                          linebreaks=True)
                        ]).get()
                        self.cleanup_tokenstreams(context, output)
                        rule.condition = output

                yara_file.insert_rule(0, another_rule)

        yara_file = yaramod.Yaramod().parse_string(r'''
rule rule_1 {
	strings:
		$str1 = "a"
	condition:
		$str1
}
''')

        visitor = RuleInserter()
        visitor.insert_rule(yara_file)

        self.assertEqual(len(yara_file.rules), 2)
        rule = yara_file.rules[1]
        cond = rule.condition
        self.assertEqual(r'''ANOTHER_RULE and (
	$str1
)''', cond.text)

        self.assertEqual(
            r'''private rule ANOTHER_RULE {
	condition:
		first_file and second_file
}

rule rule_1 {
	strings:
		$str1 = "a"
	condition:
		ANOTHER_RULE and (
			$str1
		)
}''', yara_file.text)
        expected = r'''
private rule ANOTHER_RULE
{
	condition:
		first_file and
		second_file
}

rule rule_1
{
	strings:
		$str1 = "a"
	condition:
		ANOTHER_RULE and
		(
			$str1
		)
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 16
0
    def test_modifying_visitor_delete_rules(self):
        class RulesDeleter(yaramod.ModifyingVisitor):
            def __init__(self):
                super(RulesDeleter, self).__init__()
                self.rule_map = {}
                self.rules_for_remove = set()

            def remove_disabled_rules(self,
                                      yara_file: yaramod.YaraFile) -> None:
                for rule in yara_file.rules:
                    if rule.name.startswith('delete'):
                        self.rules_for_remove.add(rule.name)

                yara_file.remove_rules(
                    lambda r: r.name in self.rules_for_remove)

                for rule in yara_file.rules:
                    rule.condition = self.modify(
                        rule.condition,
                        when_deleted=yaramod.bool_val(False).get())

            def visit_IdExpression(self, expr):
                if expr.symbol.name in self.rules_for_remove:
                    return yaramod.VisitAction.Delete

        yara_file = yaramod.Yaramod().parse_string(r'''
rule delete_rule_1 {
	strings:
		$str0 = "a"
	condition:
		$str0
}

rule rule_2 {
	strings:
		$str1 = "b"
	condition:
		$str1 or not delete_rule_1
}

rule delete_rule_3 {
	condition:
		delete_rule_1
}

rule rule_4 {
	condition:
		not delete_rule_3 and
		not rule_2
}

rule rule_5 {
	strings:
		$str1 = "c"
	condition:
		not delete_rule_1 and
		not rule_2 and
		not delete_rule_3 and
		$str1
}
''')

        visitor = RulesDeleter()
        visitor.remove_disabled_rules(yara_file)

        self.assertEqual(len(yara_file.rules), 3)

        self.assertEqual(
            r'''rule rule_2 {
	strings:
		$str1 = "b"
	condition:
		$str1
}

rule rule_4 {
	condition:
		not rule_2
}

rule rule_5 {
	strings:
		$str1 = "c"
	condition:
		not rule_2 and $str1
}''', yara_file.text)
        expected = r'''
rule rule_2
{
	strings:
		$str1 = "b"
	condition:
		$str1
}

rule rule_4
{
	condition:
		not rule_2
}

rule rule_5
{
	strings:
		$str1 = "c"
	condition:
		not rule_2 and
		$str1
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 17
0
    def test_pe_iconhash_deleter(self):
        class PeIconhashDeleter(yaramod.ModifyingVisitor):
            """Temporary pe.iconhash() remover which removes pe.iconhash()
            until we get it into the upstream.
            """
            def delete_pe_iconhash(self, yara_file):
                pe_symbol = yara_file.find_symbol('pe')
                if not pe_symbol:
                    return

                for rule in yara_file.rules:
                    rule.condition = self.modify(
                        rule.condition,
                        when_deleted=yaramod.bool_val(False).get())

            def visit_AndExpression(self, expr):
                return self._visit_logical_ops(expr)

            def visit_OrExpression(self, expr):
                return self._visit_logical_ops(expr)

            def visit_LeExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_LtExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_GeExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_GtExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_EqExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_NeqExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_PlusExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_MinusExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_MultiplyExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_DivideExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ModuloExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseXorExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseAndExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseOrExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ShiftLeftExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ShiftRightExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ContainsExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_MatchesExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_StringOffsetExpression(self, expr):
                return self._visit_string_manipulation_ops(expr)

            def visit_StringLengthExpression(self, expr):
                return self._visit_string_manipulation_ops(expr)

            def visit_FunctionCallExpression(self, expr):
                if expr.function.text == 'pe.iconhash':
                    return yaramod.VisitAction.Delete

            def _visit_logical_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                left_context = yaramod.TokenStreamContext(expr.left_operand)
                right_context = yaramod.TokenStreamContext(expr.right_operand)
                left_result = expr.left_operand.accept(self)
                right_result = expr.right_operand.accept(self)
                if left_result == yaramod.VisitAction.Delete or right_result == yaramod.VisitAction.Delete:
                    if left_result == yaramod.VisitAction.Delete:
                        new_operand = yaramod.bool_val(False).get()
                        self.cleanup_tokenstreams(left_context, new_operand)
                        expr.left_operand = new_operand
                    if right_result == yaramod.VisitAction.Delete:
                        new_operand = yaramod.bool_val(False).get()
                        self.cleanup_tokenstreams(right_context, new_operand)
                        expr.right_operand = new_operand
                else:
                    return self.default_handler(context, expr, left_result,
                                                right_result)

            def _visit_binary_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                left_result = expr.left_operand.accept(self)
                right_result = expr.right_operand.accept(self)
                if left_result == yaramod.VisitAction.Delete or right_result == yaramod.VisitAction.Delete:
                    return yaramod.VisitAction.Delete
                else:
                    self.default_handler(context, expr, left_result,
                                         right_result)

            def _visit_string_manipulation_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                index_result = None
                if expr.index_expr:
                    index_result = expr.index_expr.accept(self)
                    if index_result == yaramod.VisitAction.Delete:
                        return yaramod.VisitAction.Delete
                return self.default_handler(context, expr, index_result)

        yara_file = yaramod.Yaramod().parse_string(r'''
import "pe"

rule rule_1 {
	strings:
		$str1 = "a"
		$str2 = "b"
	condition:
		$str1 and
		(
			pe.iconhash() == "9d0bd50f710" or
			pe.iconhash() != "9d0bd50f711" or
			"9d0bd50f712" == pe.iconhash() or
			pe.iconhash() or
			$str2 or
			pe.iconhash() == "9d0bd50f714" or
			pe.iconhash() == "9d0bd50f715"
		)
}
''')

        visitor = PeIconhashDeleter()
        visitor.delete_pe_iconhash(yara_file)

        self.assertEqual(len(yara_file.rules), 1)

        self.assertEqual(
            r'''import "pe"

rule rule_1 {
	strings:
		$str1 = "a"
		$str2 = "b"
	condition:
		$str1 and (false or false or false or false or $str2 or false or false)
}''', yara_file.text)
        expected = r'''
import "pe"

rule rule_1
{
	strings:
		$str1 = "a"
		$str2 = "b"
	condition:
		$str1 and
		(
			false or
			false or
			false or
			false or
			$str2 or
			false or
			false
		)
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 18
0
    def test_cuckoo_function_replacer(self):
        class CuckooFunctionReplacer(yaramod.ModifyingVisitor):
            def __init__(self):
                super(CuckooFunctionReplacer, self).__init__()
                self.filesystem_symbol = None
                self.registry_symbol = None
                self.FILESYSTEM_REPLACE = set([
                    'cuckoo.filesystem.file_write',
                ])

                self.REGISTRY_REPLACE = set([
                    'cuckoo.registry.key_write',
                ])

                self.WHITELIST = set([
                    'cuckoo.network.http_post',
                ])

            def replace_functions(self, yara_file):
                cuckoo_symbol = yara_file.find_symbol('cuckoo')
                if not cuckoo_symbol:
                    return

                if not self.filesystem_symbol and not self.registry_symbol:
                    self.filesystem_symbol = yara_file.find_symbol(
                        'cuckoo').get_attribute('filesystem').get_attribute(
                            'file_access')
                    self.registry_symbol = yara_file.find_symbol(
                        'cuckoo').get_attribute('registry').get_attribute(
                            'key_access')

                for rule in yara_file.rules:
                    rule.condition = self.modify(
                        rule.condition,
                        when_deleted=yaramod.bool_val(False).get())

            def visit_AndExpression(self, expr):
                return self._visit_logical_ops(expr)

            def visit_OrExpression(self, expr):
                return self._visit_logical_ops(expr)

            def visit_LeExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_LtExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_GeExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_GtExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_EqExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_NeqExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_PlusExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_MinusExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_MultiplyExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_DivideExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ModuloExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseXorExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseAndExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_BitwiseOrExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ShiftLeftExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_ShiftRightExpression(self, expr):
                return self._visit_binary_ops(expr)

            def visit_StringOffsetExpression(self, expr):
                return self._visit_string_manipulation_ops(expr)

            def visit_StringLengthExpression(self, expr):
                return self._visit_string_manipulation_ops(expr)

            def _visit_logical_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                left_context = yaramod.TokenStreamContext(expr.left_operand)
                right_context = yaramod.TokenStreamContext(expr.right_operand)
                left_result = expr.left_operand.accept(self)
                right_result = expr.right_operand.accept(self)
                if left_result == yaramod.VisitAction.Delete or right_result == yaramod.VisitAction.Delete:
                    if left_result == yaramod.VisitAction.Delete:
                        new_operand = yaramod.bool_val(False).get()
                        self.cleanup_tokenstreams(left_context, new_operand)
                        expr.left_operand = new_operand
                    if right_result == yaramod.VisitAction.Delete:
                        new_operand = yaramod.bool_val(False).get()
                        self.cleanup_tokenstreams(right_context, new_operand)
                        expr.right_operand = new_operand
                else:
                    return self.default_handler(context, expr, left_result,
                                                right_result)

            def _visit_binary_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                left_result = expr.left_operand.accept(self)
                right_result = expr.right_operand.accept(self)
                if left_result == yaramod.VisitAction.Delete or right_result == yaramod.VisitAction.Delete:
                    return yaramod.VisitAction.Delete
                else:
                    self.default_handler(context, expr, left_result,
                                         right_result)

            def _visit_string_manipulation_ops(self, expr):
                context = yaramod.TokenStreamContext(expr)
                index_result = None
                if expr.index_expr:
                    index_result = expr.index_expr.accept(self)
                    if index_result == yaramod.VisitAction.Delete:
                        return yaramod.VisitAction.Delete
                return self.default_handler(context, expr, index_result)

            def visit_FunctionCallExpression(self, expr):
                function_name = expr.function.text
                if function_name.startswith('cuckoo.'):
                    if function_name in self.FILESYSTEM_REPLACE:
                        expr.function.symbol = self.filesystem_symbol
                    elif function_name in self.REGISTRY_REPLACE:
                        expr.function.symbol = self.registry_symbol
                    elif function_name not in self.WHITELIST:
                        return yaramod.VisitAction.Delete

        yara_file = yaramod.Yaramod().parse_string(r'''
import "cuckoo"

rule rule_1 {
	strings:
		$str1 = "a"
	condition:
		$str1 and
		(
			cuckoo.filesystem.file_write(/C:\\Users\\Avastian\\file1.exe/i) or
			cuckoo.filesystem.file_read(/C:\\Users\\Avastian\\file1.exe/i) or
			cuckoo.registry.key_write(/\\Microsoft\\Windows NT\\CurrentVersion/i) or
			cuckoo.network.http_post(/\/.*\/tasks\.php/) or
			cuckoo.process.executed_command(/(^|\\)a(\.exe|\s)/i)
		)
}
''')

        visitor = CuckooFunctionReplacer()
        visitor.replace_functions(yara_file)

        self.assertEqual(len(yara_file.rules), 1)
        rule = yara_file.rules[0]
        cond = rule.condition
        print(cond.text)
        self.assertEqual(
            r'''$str1 and (cuckoo.filesystem.file_access(/C:\\Users\\Avastian\\file1.exe/i) or false or cuckoo.registry.key_access(/\\Microsoft\\Windows NT\\CurrentVersion/i) or cuckoo.network.http_post(/\/.*\/tasks\.php/) or false)''',
            cond.text)

        self.assertEqual(
            r'''import "cuckoo"

rule rule_1 {
	strings:
		$str1 = "a"
	condition:
		$str1 and (cuckoo.filesystem.file_access(/C:\\Users\\Avastian\\file1.exe/i) or false or cuckoo.registry.key_access(/\\Microsoft\\Windows NT\\CurrentVersion/i) or cuckoo.network.http_post(/\/.*\/tasks\.php/) or false)
}''', yara_file.text)
        expected = r'''
import "cuckoo"

rule rule_1
{
	strings:
		$str1 = "a"
	condition:
		$str1 and
		(
			cuckoo.filesystem.file_access(/C:\\Users\\Avastian\\file1.exe/i) or
			false or
			cuckoo.registry.key_access(/\\Microsoft\\Windows NT\\CurrentVersion/i) or
			cuckoo.network.http_post(/\/.*\/tasks\.php/) or
			false
		)
}
'''
        self.assertEqual(expected, yara_file.text_formatted)
Exemplo n.º 19
0
    def test_custom_module_enhancing_known_module(self):
        modules = yaramod.Yaramod(yaramod.Features.AllCurrent, "./tests/python/testing_modules").modules

        # module cuckoo
        self.assertTrue("cuckoo" in modules)
        cuckoo_symbol = modules["cuckoo"].structure
        self.assertEqual("cuckoo", cuckoo_symbol.name)
        self.assertTrue(cuckoo_symbol.is_structure)
        cuckoo_attributes = cuckoo_symbol.attributes

        # module pe - added of an overload
        self.assertTrue("pe" in modules)
        pe_symbol = modules["pe"].structure
        self.assertEqual("pe", pe_symbol.name)
        pe_attributes = pe_symbol.attributes

        # other pe json does not delete functions from base pe json:
        self.assertTrue("MACHINE_AM33" in pe_attributes)
        machine_symbol = pe_attributes["MACHINE_AM33"]
        self.assertTrue(machine_symbol.is_value)
        self.assertEqual(machine_symbol.data_type, yaramod.ExpressionType.Int)

        # no problem with multiple definitions of the same symbol if those definitions are compatible:
        self.assertTrue("MACHINE_TEST_VALUE" in pe_attributes)
        machine_symbol = pe_attributes["MACHINE_TEST_VALUE"]
        self.assertTrue(machine_symbol.is_value)
        self.assertEqual(machine_symbol.data_type, yaramod.ExpressionType.Int)

        self.assertTrue("sections" in pe_attributes)
        section_array_symbol = pe_attributes['sections']
        self.assertEqual(section_array_symbol.name, 'sections')
        self.assertTrue(section_array_symbol.is_array)
        self.assertEqual(section_array_symbol.element_type, yaramod.ExpressionType.Object)
        self.assertEqual(section_array_symbol.documentation[0:10], 'Individual')
        section_symbol = section_array_symbol.structure
        self.assertEqual(section_symbol.name, 'sections')
        self.assertTrue(section_symbol.is_structure)
        section_attributes = section_symbol.attributes

        # pe.sections.characteristics still exists:
        self.assertTrue("virtual_address" in section_attributes)
        # pe.sections.test_sections_value is added:
        self.assertTrue("test_sections_value" in section_attributes)
        test_section_value_symbol = section_attributes['test_sections_value']
        self.assertEqual(test_section_value_symbol.name, 'test_sections_value')
        self.assertTrue(test_section_value_symbol.is_value)
        self.assertTrue(test_section_value_symbol.data_type, yaramod.ExpressionType.String)

        self.assertTrue("rich_signature" in pe_attributes)
        rich_signature_symbol = pe_attributes['rich_signature']
        self.assertTrue(rich_signature_symbol.is_structure)
        rich_signature_attributes = rich_signature_symbol.attributes

        self.assertTrue("test_value" in rich_signature_attributes)
        self.assertTrue("version" in rich_signature_attributes)
        version_symbol = rich_signature_attributes['version']
        self.assertTrue(version_symbol.is_function)
        version_overloads = version_symbol.overloads
        self.assertEqual(len(version_overloads), 3)
        self.assertEqual(version_overloads[0], [yaramod.ExpressionType.Int])
        self.assertEqual(version_overloads[1], [yaramod.ExpressionType.Int, yaramod.ExpressionType.Int])
        self.assertEqual(version_overloads[2], [yaramod.ExpressionType.Int, yaramod.ExpressionType.String])
        version_overloads_names = version_symbol.argument_names
        self.assertEqual(version_overloads_names[0], ["version"])
        self.assertEqual(version_overloads_names[1], ["version", "toolid"])
        self.assertEqual(version_overloads_names[2], ["version", "test string argument"])