def test_empty_string(self): inputTags = r''' rule thirteen { meta: my_identifier_1 = "" my_identifier_2 = 24 my_identifier_3 = true strings: $my_text_string = "text here" $my_hex_string = { E2 34 A1 C8 23 FB } condition: $my_text_string or $my_hex_string } ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputTags, isPrintDebug=False) for rule in result: rule_name = rule["rule_name"] if rule_name == 'thirteen': self.assertTrue(len(rule['metadata']) == 3)
def test_empty_string(self): inputTags = r''' rule thirteen { meta: my_identifier_1 = "" my_identifier_2 = 24 my_identifier_3 = true strings: $my_text_string = "text here" $my_hex_string = { E2 34 A1 C8 23 FB } condition: $my_text_string or $my_hex_string } ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputTags, isPrintDebug=False) for rule in result: rule_name = rule["rule_name"] if rule_name == 'thirteen': self.assertTrue(len(rule['metadata']) == 3 )
def test_rule_name_imports_and_scopes(self): inputStringNIS = r''' rule four {meta: i = "j" strings: $a = "b" condition: true } global rule five {meta: i = "j" strings: $a = "b" condition: false } private rule six {meta: i = "j" strings: $a = "b" condition: true } global private rule seven {meta: i = "j" strings: $a = "b" condition: true } import "lib1" rule eight {meta: i = "j" strings: $a = "b" condition: true } import "lib1" import "lib2" rule nine {meta: i = "j" strings: $a = "b" condition: true } import "lib1" import "lib2" private global rule ten {meta: i = "j" strings: $a = "b" condition: true } ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputStringNIS, isPrintDebug=False) self.assertEqual(len(result), 7) for rule in result: rule_name = rule["rule_name"] if rule_name == 'four': self.assertTrue('scopes' not in rule) self.assertTrue('imports' not in rule) if rule_name == 'five': self.assertTrue('imports' not in rule) self.assertTrue('global' in rule['scopes']) if rule_name == 'six': self.assertTrue('imports' not in rule) self.assertTrue('private' in rule['scopes']) if rule_name == 'seven': self.assertTrue('imports' not in rule) self.assertTrue('private' in rule['scopes'] and 'global' in rule['scopes']) if rule_name == 'eight': self.assertTrue('"lib1"' in rule['imports']) self.assertTrue('scopes' not in rule) if rule_name == 'nine': self.assertTrue('"lib1"' in rule['imports'] and '"lib2"' in rule['imports']) self.assertTrue('scopes' not in rule) if rule_name == 'ten': self.assertTrue('"lib1"' in rule['imports'] and '"lib2"' in rule['imports']) self.assertTrue('global' in rule['scopes'] and 'private' in rule['scopes'])
def test_tags(self): inputTags = r''' rule eleven: tag1 {meta: i = "j" strings: $a = "b" condition: true } rule twelve : tag1 tag2 {meta: i = "j" strings: $a = "b" condition: true } ''' result = interp.parseString(inputTags, isPrintDebug=False) for rule in result: rule_name = rule["rule_name"] if rule_name == 'eleven': self.assertTrue(len(rule['tags']) == 1 and 'tag1' in rule['tags']) if rule_name == 'twelve': self.assertTrue(len(rule['tags']) == 2 and 'tag1' in rule['tags'] and 'tag2' in rule['tags'])
def query_by_hash(qhash): yara = redis.get('query:' + qhash) try: rules = interp.parseString(yara) except Exception as e: return error_page(yara, 'PLYara failed (not my fault): ' + str(e)) if len(rules) > 1: return error_page(yara, 'More than one rule specified') rule_name = rules[0].get('rule_name') try: parser = YaraParser(rules[0]) pre_parsed = parser.pre_parse() parsed = parser.parse() except Exception as e: return error_page(yara, 'YaraParser failed (msm\'s fault): ' + str(e)) matches = redis.smembers('matches:' + qhash) false_positives = redis.smembers('false_positives:' + qhash) job = redis.hgetall('job:' + qhash) debug = 'debug' in request.args error = job.get('error') body = render_template('index.html', yara=yara, pre_parsed=pre_parsed, parsed=parsed, job=job, matches=matches, errors=error, false_positives=false_positives, debug=debug, saved_rules=get_saved_rules(), qhash=qhash, rule_name=rule_name, repo_url=config.REPO_URL) return body
def test_multiple_rules(self): inputString = r''' rule FirstRule { meta: author = "Andrés Iniesta" date = "2015-01-01" strings: $a = "hark, a \"string\" here" fullword ascii $b = { 00 22 44 66 88 aa cc ee } condition: all of them } import "bingo" import "bango" rule SecondRule : aTag { meta: author = "Ivan Rakitić" date = "2015-02-01" strings: $x = "hi" $y = /state: (on|off)/ wide $z = "bye" condition: for all of them : ( # > 2 ) } rule ThirdRule {condition: uint32(0) == 0xE011CFD0} ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputString, isPrintDebug=False) self.assertEqual(len(result), 3) self.assertEqual(result[0]['metadata']['author'], '"Andrés Iniesta"') self.assertEqual(result[0]['metadata']['date'], '"2015-01-01"') self.assertTrue([x["name"] for x in result[0]['strings']] == ['$a', '$b'])
def test_multiple_rules(self): inputString = r''' rule FirstRule { meta: author = "Andrés Iniesta" date = "2015-01-01" strings: $a = "hark, a \"string\" here" fullword ascii $b = { 00 22 44 66 88 aa cc ee } condition: all of them } import "bingo" import "bango" rule SecondRule : aTag { meta: author = "Ivan Rakitić" date = "2015-02-01" strings: $x = "hi" $y = /state: (on|off)/ wide $z = "bye" condition: for all of them : ( # > 2 ) } rule ThirdRule {condition: uint32(0) == 0xE011CFD0} ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputString, isPrintDebug=False) self.assertEqual(len(result), 3) self.assertEqual(result[0]['metadata']['author'], '"Andrés Iniesta"') self.assertEqual(result[0]['metadata']['date'], '"2015-01-01"') self.assertTrue([x["name"] for x in result[0]['strings']] == ['$a','$b'])
def test_tags(self): inputTags = r''' rule eleven: tag1 {meta: i = "j" strings: $a = "b" condition: true } rule twelve : tag1 tag2 {meta: i = "j" strings: $a = "b" condition: true } ''' interp.ParserInterpreter.rules = [] result = interp.parseString(inputTags, isPrintDebug=False) for rule in result: rule_name = rule["rule_name"] if rule_name == 'eleven': self.assertTrue( len(rule['tags']) == 1 and 'tag1' in rule['tags']) if rule_name == 'twelve': self.assertTrue( len(rule['tags']) == 2 and 'tag1' in rule['tags'] and 'tag2' in rule['tags'])
#!/usr/bin/env python #-*- coding: utf-8 -*- import operator import os import sys sys.path.insert(0, os.getcwd()) import plyara.interp as interp # Plyara is a script that lexes and parses a file consisting of one more Yara # rules into a python dictionary representation. if __name__ == '__main__': file_to_analyze = sys.argv[1] rulesDict = interp.parseString(open(file_to_analyze).read()) authors = {} imps = {} meta_keys = {} max_strings = [] max_string_len = 0 tags = {} rule_count = 0 for rule in rulesDict: rule_count += 1 # Imports if 'imports' in rule: for imp in rule['imports']: imp = imp.replace('"', '')
import operator import os import sys sys.path.insert(0, os.getcwd()) import plyara.interp as interp if __name__ == '__main__': file_to_analyze = sys.argv[1] print("...parsing file...") rulesDict = interp.parseString(open(file_to_analyze).read()) print("...analyzing dictionary...") authors = {} imps = {} meta_keys = {} max_strings = [] max_string_len = 0 tags = {} rule_count = 0 for rule in rulesDict: rule_count += 1 #Imports if 'imports' in rule: for imp in rule['imports']: imp = imp.replace('"','')
def execute_job(job_id, hash, yara_rule): logging.info('Parsing...') redis.hmset(job_id, { 'status': 'processing', 'timestamp': time.time(), }) try: rules = interp.parseString(yara_rule) parser = YaraParser(rules[0]) parsed = parser.parse() except Exception as e: logging.exception(e) raise RuntimeError('Failed to parse Yara') redis.hmset(job_id, { 'status': 'querying', 'timestamp': time.time(), }) logging.info('Querying backend...') result = db.query(parsed) if 'error' in result: raise RuntimeError(result['error']) job = redis.hgetall(job_id) files = [f for f in result['files'] if f.strip()] logging.info('Database responded with {} files'.format(len(files))) if 'max_files' in job and int(job['max_files']) > 0: files = files[:int(job['max_files'])] redis.hmset(job_id, { 'total_files': len(files), 'files_processed': 0, }) logging.info('Compiling Yara') try: rule = yara.compile(source=yara_rule) except SyntaxError as e: logging.exception('Yara parse error') raise e for file_ndx, file_path in enumerate(files): matches = rule.match(data=open(file_path, 'rb').read()) if matches: logging.info('Processed (match): {}'.format(file_path)) redis.sadd('matches:' + hash, file_path) else: logging.info('Processed (nope ): {}'.format(file_path)) redis.sadd('false_positives:' + hash, file_path) redis.hmset(job_id, { 'files_processed': file_ndx + 1, }) status = redis.hget(job_id, 'status') if status == 'cancelled': logging.info('Job cancelled') return redis.hmset(job_id, { 'status': 'done', }) logging.info('Done')