summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjvoisin2014-02-12 02:10:08 +0000
committerjvoisin2014-02-12 02:10:08 +0000
commitd152570e1176d2ed79fd0bc4c49d1a12259e7ab2 (patch)
treef3d64c6028af570473c52e66f0365fbed8850132
Add a peid2yara script
-rw-r--r--peid_to_yara.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/peid_to_yara.py b/peid_to_yara.py
new file mode 100644
index 0000000..975152e
--- /dev/null
+++ b/peid_to_yara.py
@@ -0,0 +1,113 @@
1#!/usr/bin/env python
2# encoding: utf-8
3#
4# Tested on Linux (Ubuntu), Windows XP/7, and Mac OS X
5#
6'''
7untitled.py
8
9Created by Matthew Richard on 2010-03-12.
10Ported to py3 by Julien (jvoisin) Voisin on feb2014
11Copyright (c) 2010. All rights reserved.
12'''
13
14import os
15import re
16import argparse
17import collections
18
19
20def main():
21 parser = argparse.ArgumentParser(description='PEiD to yara rules converter')
22 parser.add_argument('-n', '--no-ep', dest='no_ep', action='store_true',
23 default=False, help='no entrypoint restriction')
24 parser.add_argument('files', metavar='files', type=str, nargs='+',
25 help='scanned filenames')
26 parser.add_argument('-o', '--output-file', action='store', dest='outfile',
27 help='output filename')
28
29 opts = parser.parse_args()
30
31 if opts.outfile is None:
32 parser.error('You must specify an output filename!\n')
33 elif opts.files is None:
34 parser.error('You must supply at least one filename!\n')
35 else:
36 for fin in opts.files:
37 if not os.path.isfile(fin):
38 parser.error('%s does not exist' % fin)
39
40 # yara rule template from which rules will be created
41 yara_rule = '''
42rule %s
43{
44strings:
45 %s
46condition:
47 %s
48}
49
50 '''
51 rules = collections.defaultdict(lambda: set(), {})
52
53 # read the PEiD signature files
54 data = ' '.join([open(f, 'r').read() for f in opts.files])
55
56 # every signature takes the form of
57 # [signature_name]
58 # signature = hex signature
59 # ep_only = (true|false)
60 signature = re.compile(r'''
61 \[\d*
62 ([^(?:\->)\n]{1,128}) # This is the rule name
63 (?:\->)?[^\]]*\]\s*\n # We don't care about content after a "->"
64 signature\ =\ (?:\?.\ )* # Signature pattern can't start with ??
65 ((?:[0-9A-Fa-f?]{2}\ )* # Only match hex pairs
66 [0-9A-Fa-f?]{2})\s*\n # Get the terminal pair
67 ep_only\ =\ (true|false)\s*\n
68 ''', re.MULTILINE | re.VERBOSE)
69
70 # rule name has the same constraints as a C variable name
71 rules_cpt = 0
72 double_cpt = 0
73 name_filter = re.compile(r'(\W)')
74 for match in signature.finditer(data):
75 name = name_filter.sub('_', match.group(1)).rstrip('_')
76 if (match.group(2), match.group(3)) in rules[name]:
77 double_cpt +=1
78 rules[name].add((match.group(2), match.group(3)))
79 rules_cpt += 1
80 print('[+] Found %d signatures (%d duplicates) in PEiD input file' %
81 (rules_cpt, double_cpt))
82
83 output = ''
84 for rule in list(rules.keys()):
85 detects = ''
86 conds = '\t'
87 counter = 0
88 for (detect, use_ep) in rules[rule]:
89 # create each new rule using a unique numeric value
90 # to allow for multiple criteria and no collisions
91 detects += '\t$a%d = { %s }\n' % (counter, detect)
92
93 if counter > 0:
94 conds += ' or '
95
96 # if the rule specifies it should be at EP we add
97 # the yara specifier 'at entrypoint'
98 conds += '$a%d' % counter
99 if use_ep == 'true' and opts.no_ep is False:
100 conds += ' at entrypoint'
101 counter += 1
102
103 # add the rule to the output
104 output += yara_rule % (rule, detects, conds)
105
106 # could be written to an output file
107 with open(opts.outfile, 'w') as fout:
108 fout.write(output)
109
110 print('[+] Wrote %d rules to %s' % (len(rules), opts.outfile))
111
112if __name__ == '__main__':
113 main()