Package rekall :: Package plugins :: Package tools :: Module yara_support
[frames] | no frames]

Source Code for Module rekall.plugins.tools.yara_support

  1  # Rekall Memory Forensics 
  2  # Copyright 2016 Google Inc. All Rights Reserved. 
  3  # 
  4  # This program is free software; you can redistribute it and/or modify 
  5  # it under the terms of the GNU General Public License as published by 
  6  # the Free Software Foundation; either version 2 of the License, or (at 
  7  # your option) any later version. 
  8  # 
  9  # This program is distributed in the hope that it will be useful, but 
 10  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 12  # General Public License for more details. 
 13  # 
 14  # You should have received a copy of the GNU General Public License 
 15  # along with this program; if not, write to the Free Software 
 16  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
 17  # 
 18   
 19  """Routines for manipulating yara rule definitions.""" 
 20   
 21  import string 
 22  import sys 
 23  import yaml 
 24  import pyparsing 
 25   
 26   
 27  _RULE = pyparsing.Keyword("rule") 
 28  _KEYWORD = (pyparsing.Literal("wide") | 
 29              pyparsing.Literal("fullword") | 
 30              pyparsing.Literal("ascii") | 
 31              pyparsing.Literal("nocase")) 
 32   
 33  _IDENTIFIER = pyparsing.Word(pyparsing.alphanums + '_' + "$") 
 34  _REGEX = (pyparsing.QuotedString("/", escChar="\\", unquoteResults=False) + 
 35            pyparsing.Optional(pyparsing.Word("sig"))) 
 36  _LEFT_CURLY = pyparsing.Literal("{") 
 37  _RIGHT_CURLY = pyparsing.Literal("}") 
 38  _COLON = pyparsing.Literal(':') 
 39  _EQUALS = pyparsing.Literal("=") 
 40   
 41   
42 -def anything_beetween(opener_and_closer):
43 """Builds a (pyparsing) parser for the content inside delimiters. 44 45 Args: 46 opener_and_closer: a string containing two elements: opener and closer 47 48 Returns: 49 A (pyparsing) parser for the content inside delimiters. 50 """ 51 opener = pyparsing.Literal(opener_and_closer[0]) 52 closer = pyparsing.Literal(opener_and_closer[1]) 53 char_removal_mapping = dict.fromkeys(map(ord, opener_and_closer)) 54 other_chars = unicode(string.printable).translate(char_removal_mapping) 55 word_without_delimiters = pyparsing.Word(other_chars).setName( 56 "other_chars") 57 anything = pyparsing.Forward() 58 delimited_block = opener + anything + closer 59 # pylint: disable=expression-not-assigned 60 anything << pyparsing.ZeroOrMore( 61 word_without_delimiters.setName("word_without_delimiters") 62 | delimited_block.setName("delimited_block") 63 ) 64 65 # Combine all the parts into a single string. 66 return pyparsing.Combine(anything)
67
68 -def anything_in(opener_and_closer):
69 opener = opener_and_closer[0] 70 closer = opener_and_closer[1] 71 anything = anything_beetween(opener_and_closer) 72 return opener + anything + closer
73
74 -def anything_in_curly():
75 return anything_in('{}')
76
77 -def meta_section():
78 return pyparsing.Group( 79 pyparsing.Literal("meta") + 80 _COLON + 81 pyparsing.OneOrMore( 82 statement() 83 ).setResultsName("statements") 84 ).setResultsName("meta")
85
86 -def statement():
87 return pyparsing.Group( 88 _IDENTIFIER.setResultsName("lhs") + _EQUALS + 89 pyparsing.Combine( 90 (anything_in_curly() | 91 pyparsing.QuotedString("'", escChar="\\", unquoteResults=False) | 92 pyparsing.QuotedString("\"", escChar="\\", unquoteResults=False) | 93 _REGEX) + 94 pyparsing.ZeroOrMore(_KEYWORD), 95 adjacent=False, 96 joinString=" ", 97 ).setResultsName("rhs") 98 )
99
100 -def strings_section():
101 return pyparsing.Group( 102 pyparsing.Literal("strings") + 103 _COLON + 104 pyparsing.OneOrMore(statement()).setResultsName("statements") 105 ).setResultsName("strings")
106
107 -def condition_section():
108 return (_IDENTIFIER + 109 _COLON + 110 pyparsing.SkipTo(_RIGHT_CURLY).setResultsName("statement") 111 ).setResultsName("condition")
112
113 -def section():
114 return (strings_section() | 115 meta_section() | 116 condition_section())
117
118 -def rule():
119 return (_RULE + 120 _IDENTIFIER.setResultsName("name") + 121 _LEFT_CURLY + 122 pyparsing.OneOrMore(section()) + 123 _RIGHT_CURLY)
124
125 -def yara_parser():
126 return pyparsing.OneOrMore(rule())
127
128 -def rule_to_ast(parsed_rule):
129 condition = parsed_rule["condition"]["statement"] 130 131 result = dict(name=parsed_rule["name"], 132 meta={}, 133 strings=[], 134 condition=condition) 135 136 for x in parsed_rule.get("meta", {}).get("statements", []): 137 result["meta"][x["lhs"]] = x["rhs"] 138 139 for x in parsed_rule.get("strings", {}).get("statements", []): 140 result["strings"].append((x["lhs"], x["rhs"])) 141 142 return result
143
144 -def parse_yara_to_ast(yara_rules):
145 """Parse a yara rules file into a python AST.""" 146 # Strip c like comments. 147 yara_rules = pyparsing.cppStyleComment.suppress().transformString( 148 yara_rules) 149 150 result = [] 151 for rules, _, _ in rule().parseWithTabs().scanString(yara_rules): 152 try: 153 result.append(rule_to_ast(rules)) 154 except Exception: 155 pass 156 157 return result
158
159 -def ast_to_yara(parsed_rules):
160 result = [] 161 for rule_ast in parsed_rules: 162 result.append("rule %s {" % rule_ast["name"]) 163 metadata = rule_ast.get("meta") 164 if metadata: 165 result.append(" meta:") 166 for k, v in metadata.iteritems(): 167 result.append(" %s = %s" % (k, v)) 168 169 if rule_ast.get("strings"): 170 result.append(" strings:") 171 for k, v in sorted(rule_ast["strings"]): 172 result.append(" %s = %s" % (k, v)) 173 174 result.append(" condition: %s" % rule_ast["condition"]) 175 result.append(" }") 176 return "\n".join(result)
177 178 179 if __name__ == "__main__": 180 action = sys.argv[1] 181 filename = sys.argv[2] 182 if action == "parse": 183 data = open(filename).read() 184 print yaml.safe_dump( 185 parse_yara_to_ast(data), 186 default_flow_style=False) 187 elif action == "encode": 188 data = open(filename).read() 189 print ast_to_yara(yaml.safe_load(data)) 190 else: 191 raise RuntimeError("Unknown action %s" % action) 192